Как работает шаблон стратегии?
Как это работает, для чего оно используется и когда его следует использовать?
6 ответов
Давайте объясним шаблон стратегии простым способом:
У вас есть класс Car()
с методом run()
Таким образом, вы используете его таким образом на псевдо-языке:
mycar = new Car()
mycar.run()
Теперь вы можете изменить run()
поведение на лету, пока программа выполняется. Например, вы можете смоделировать отказ двигателя или использовать кнопку "повышения" в видеоигре.
Есть несколько способов сделать это моделирование: использование условных операторов и переменной флага - один из способов. Шаблон стратегии другой: он делегирует поведение run()
метод к другому классу:
Class Car()
{
this.motor = new Motor(this)
// passing "this" is important for the motor so it knows what it is running
method run()
{
this.motor.run()
}
method changeMotor(motor)
{
this.motor = motor
}
}
Если вы хотите изменить поведение автомобиля, вы можете просто изменить мотор. (Легче в программе, чем в реальной жизни, верно?;-))
Это очень полезно, если у вас много сложных состояний: вы можете изменять и поддерживать их гораздо проще.
проблема
Шаблон стратегии используется для решения проблем, которые могут (или предполагается, что они могут быть) реализованы или решены различными стратегиями и которые имеют четко определенный интерфейс для таких случаев. Каждая стратегия полностью справедлива сама по себе, при этом некоторые стратегии предпочтительнее в определенных ситуациях, которые позволяют приложению переключаться между ними во время выполнения.
Пример кода
namespace StrategyPatterns
{
// Interface definition for a Sort algorithm
public interface ISort
{
void Sort(List<string> list)
}
// QuickSort implementation
public class CQuickSorter : ISort
{
void Sort(List<string> list)
{
// Here will be the actual implementation
}
}
// BubbleSort implementation
public class CBubbleSort : ISort
{
void Sort(List<string> list)
{
// The actual implementation of the sort
}
}
// MergeSort implementation
public class CMergeSort : ISort
{
void Sort(List<string> list)
{
// Again the real implementation comes here
}
}
public class Context
{
private ISort sorter;
public Context(ISort sorter)
{
// We pass to the context the strategy to use
this.sorter = sorter;
}
public ISort Sorter
{
get{return sorter;)
}
}
public class MainClass
{
static void Main()
{
List<string> myList = new List<string>();
myList.Add("Hello world");
myList.Add("Another item");
myList.Add("Item item");
Context cn = new Context(new CQuickSorter());
// Sort using the QuickSort strategy
cn.Sorter.Sort(myList);
myList.Add("This one goes for the mergesort");
cn = new Context(new CMergeSort());
// Sort using the merge sort strategy
cn.Sorter.Sort(myList);
}
}
}
- Что такое стратегия? Стратегия - это план действий, предназначенный для достижения конкретной цели;
- "Определите семейство алгоритмов, инкапсулируйте каждый и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют ". (Банда четырех);
- Определяет набор классов, каждый из которых представляет потенциальное поведение. Переключение между этими классами меняет поведение приложения. (Стратегия);
- Это поведение может быть выбрано во время выполнения (с использованием полиморфизма) или во время разработки;
- Захватить абстракцию в интерфейсе, похоронить детали реализации в производных классах;
- Альтернативой Стратегии является изменение поведения приложения с помощью условной логики. (ПЛОХОЙ);
Использование этого шаблона упрощает добавление или удаление определенного поведения без необходимости перекодирования и повторного тестирования всего или частей приложения;
Хорошо использует:
- Когда у нас есть набор схожих алгоритмов и его нужно переключать между ними в разных частях приложения. С помощью Pattern Pattern можно избежать ошибок и облегчить обслуживание;
- Когда мы хотим добавить новые методы в суперкласс, которые не обязательно имеют смысл для каждого подкласса. Вместо того чтобы использовать интерфейс традиционным способом, добавляя новый метод, мы используем переменную экземпляра, которая является подклассом нового интерфейса Functionality. Это называется Композицией: вместо наследования способности через наследование класс состоит из Объектов с нужной способностью;
Тесно связанным паттерном является паттерн делегата; в обоих случаях часть работы передается другому компоненту. Если я правильно понимаю, разница между этими шаблонами заключается в следующем (и, пожалуйста, исправьте меня, если я ошибаюсь):
В шаблоне Delegate экземпляр делегата создается классом включения (делегирования); это позволяет повторно использовать код по составу, а не по наследству. Вмещающий класс может знать о конкретном типе делегата, например, если он вызывает его конструктор (в отличие от использования фабрики).
В шаблоне " Стратегия" компонент, который выполняет стратегию, является зависимостью, предоставляемой включающему (использующему) компоненту через его конструктор или установщик (в соответствии с вашей религией). Компонент using не знает, какая стратегия используется; стратегия всегда вызывается через интерфейс.
Кто-нибудь знает другие различия?
Непосредственно из статьи Википедии "Шаблон стратегии":
Шаблон стратегии полезен в ситуациях, когда необходимо динамически менять алгоритмы, используемые в приложении. Шаблон стратегии предназначен для обеспечения средств для определения семейства алгоритмов, инкапсуляции каждого из них как объекта и обеспечения их взаимозаменяемости. Шаблон стратегии позволяет алгоритмам варьироваться независимо от клиентов, которые их используют.
Чтобы добавить к уже великолепным ответам: шаблон стратегии очень похож на передачу функции (или функций) в другую функцию. В стратегии это делается путем оборачивания указанной функции в объект с последующей передачей объекта. Некоторые языки могут передавать функции напрямую, поэтому им вообще не нужен шаблон. Но другие языки не могут передавать функции, но могут передавать объекты; шаблон тогда применяется.
Особенно в Java-подобных языках вы обнаружите, что тип zoo языка довольно мал и что единственный способ расширить его - создать объекты. Следовательно, большинство решений проблем состоит в том, чтобы придумать образец; способ составления объектов для достижения конкретной цели. Языки с более богатыми типами зоопарков часто имеют более простые способы решения проблем - но более богатые типы также означают, что вам придется тратить больше времени на изучение системы типов. Языки с динамической дисциплиной типизации часто находят хитрый способ решения проблемы.