Стратегия — это поведенческий паттерн, выносит набор алгоритмов в собственные классы и делает их взаимозаменимыми.
Другие объекты содержат ссылку на объект-стратегию и делегируют ей работу. Программа может подменить этот объект другим, если требуется иной способ решения задачи.
Сложность:
Популярность:
Применимость: Стратегия часто используется в C++ коде, особенно там, где нужно подменять алгоритм во время выполнения программы. Многие примеры стратегии можно заменить простыми lambda-выражениями.
Признаки применения паттерна: Класс делегирует выполнение вложенному объекту абстрактного типа или интерфейса.
Концептуальный пример
Этот пример показывает структуру паттерна Стратегия , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
/**
* Интерфейс Стратегии объявляет операции, общие для всех поддерживаемых версий
* некоторого алгоритма.
*
* Контекст использует этот интерфейс для вызова алгоритма, определённого
* Конкретными Стратегиями.
*/
class Strategy
{
public:
virtual ~Strategy() = default;
virtual std::string doAlgorithm(std::string_view data) const = 0;
};
/**
* Контекст определяет интерфейс, представляющий интерес для клиентов.
*/
class Context
{
/**
* @var Strategy Контекст хранит ссылку на один из объектов Стратегии.
* Контекст не знает конкретного класса стратегии. Он должен работать со
* всеми стратегиями через интерфейс Стратегии.
*/
private:
std::unique_ptr<Strategy> strategy_;
/**
* Обычно Контекст принимает стратегию через конструктор, а также
* предоставляет сеттер для её изменения во время выполнения.
*/
public:
explicit Context(std::unique_ptr<Strategy> &&strategy = {}) : strategy_(std::move(strategy))
{
}
/**
* Обычно Контекст позволяет заменить объект Стратегии во время выполнения.
*/
void set_strategy(std::unique_ptr<Strategy> &&strategy)
{
strategy_ = std::move(strategy);
}
/**
* Вместо того, чтобы самостоятельно реализовывать множественные версии
* алгоритма, Контекст делегирует некоторую работу объекту Стратегии.
*/
void doSomeBusinessLogic() const
{
if (strategy_) {
std::cout << "Context: Sorting data using the strategy (not sure how it'll do it)\n";
std::string result = strategy_->doAlgorithm("aecbd");
std::cout << result << "\n";
} else {
std::cout << "Context: Strategy isn't set\n";
}
}
};
/**
* Конкретные Стратегии реализуют алгоритм, следуя базовому интерфейсу
* Стратегии. Этот интерфейс делает их взаимозаменяемыми в Контексте.
*/
class ConcreteStrategyA : public Strategy
{
public:
std::string doAlgorithm(std::string_view data) const override
{
std::string result(data);
std::sort(std::begin(result), std::end(result));
return result;
}
};
class ConcreteStrategyB : public Strategy
{
std::string doAlgorithm(std::string_view data) const override
{
std::string result(data);
std::sort(std::begin(result), std::end(result), std::greater<>());
return result;
}
};
/**
* Клиентский код выбирает конкретную стратегию и передаёт её в контекст. Клиент
* должен знать о различиях между стратегиями, чтобы сделать правильный выбор.
*/
void clientCode()
{
Context context(std::make_unique<ConcreteStrategyA>());
std::cout << "Client: Strategy is set to normal sorting.\n";
context.doSomeBusinessLogic();
std::cout << "\n";
std::cout << "Client: Strategy is set to reverse sorting.\n";
context.set_strategy(std::make_unique<ConcreteStrategyB>());
context.doSomeBusinessLogic();
}
int main()
{
clientCode();
return 0;
}
Output.txt: Результат выполнения
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
abcde
Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
edcba
Стратегия на других языках программирования