Это позволяет выбирать алгоритм путем определения соответствующего класса.
Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов клиентов, которые его используют.
Проблема: по типу клиента (или по типу обрабатываемых данных) выбрать подходящий алгоритм, который следует применить.
Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».
Решение: отделение процедуры выбора алгоритма от его реализации.
Это позволяет сделать выбор на основании контекста.
- Класс Strategy определяет, как будут использоваться различные алгоритмы.
- Конкретные классы ConcreteStrategy реализуют эти различные алгоритмы.
- Класс Context использует конкретные классы ConcreteStrategy посредством ссылки на конкретный тип абстрактного класса Strategy.
- Классы Strategy и Context взаимодействуют с целью реализации выбранного алгоритма (в некоторых случаях классу Strategy требуется посылать запросы классу Context).
- Класс Context пересылает классу Strategy запрос, поступивший от его класса клиента.
|
|
Этот паттерн инкапсулирует семейство алгоритмов, делая их взаимозаменяемыми.
Применять его целесообразно в следующих случаях:
• Имеются родственные классы, отличающеюся только поведением. Стратегия позволяет гибко конфигурировать класс, задавая одно из возможных поведений;
• Требуется иметь несколько разных вариантов алгоритма.
Например, можно определить два варианта алгоритма, один из которых требует больше времени, а другой — больше памяти.
Кроме того, с помощью стратегии легко определить поведение класса по умолчанию.
Варианты алгоритмов могут быть реализованы в виде иерархии классов, что позволяет вычленить общую для всех классов функциональность.
Инкапсулированные алгоритмы можно затем применять в разных контекстах;
• в алгоритме хранятся данные, о которых клиент не должен «знать». Стратегия позволяет не раскрывать сложные, специфичные для алгоритма структуры данных;
• в классе определено много вариантов поведения, что представлено разветвленными условными операторами. В этом случае проще перенести код из ветвей в отдельные классы стратегий.
Структура паттерна приведена на рис.
Паттерн состоит из следующих классов:
• Strategy (стратегия) объявляет общий для всех поддерживаемых алгоритмов интерфейс.
Класс Context пользуется этим интерфейсом для вызова конкретного алгоритма, определенного в классе ConcreteStrategy;
• ConcreteStrategy (конкретная стратегия) — наследник класса Strategy. Реализует алгоритм, использующий интерфейс, объявленный в классе Strategy;
• Context (контекст) конфигурируется объектом класса ConcreteStrategy.
|
|
Хранит ссылку на объект класса Strategy и может определять интерфейс, который позволяет объекту Strategy получить доступ к данным контекста.
Таким образом, объект Context делегирует реализацию конкретного алгоритма поведения объекту Strategy, что дает возможность гибко изменять поведение объекта.
#include <iostream>
Class Strategy
{ public:
virtual ~Strategy() {}
virtual void use(void) = 0;
};
Class Strategy_1: public Strategy
{
public:
void use(void){ std::cout << "Strategy_1" << std::endl; };
};
Class Strategy_2: public Strategy
{
public:
void use(void){ std::cout << "Strategy_2" << std::endl; };
};
Class Strategy_3: public Strategy
{
public:
void use(void){ std::cout << "Strategy_3" << std::endl; };
};
Class Context
{ protected:
Strategy* operation;
public:
virtual ~Context() {}
virtual void useStrategy(void) = 0;
virtual void setStrategy(Strategy* v) = 0;
};