1+ #include < iostream>
2+ #include < vector>
3+ #include < string>
4+ #include < algorithm>
5+
6+ /* *
7+ * EN: Strategy Design Pattern
8+ *
9+ * Intent: Lets you define a family of algorithms, put each of them into a
10+ * separate class, and make their objects interchangeable.
11+ *
12+ * RU: Паттерн Стратегия
13+ *
14+ * Назначение: Определяет семейство схожих алгоритмов и помещает каждый из них в
15+ * собственный класс, после чего алгоритмы можно взаимозаменять прямо во время
16+ * исполнения программы.
17+ */
18+
19+ /* *
20+ * EN: The Strategy interface declares operations common to all supported
21+ * versions of some algorithm.
22+ *
23+ * The Context uses this interface to call the algorithm defined by Concrete
24+ * Strategies.
25+ *
26+ * RU: Интерфейс Стратегии объявляет операции, общие для всех поддерживаемых
27+ * версий некоторого алгоритма.
28+ *
29+ * Контекст использует этот интерфейс для вызова алгоритма, определённого
30+ * Конкретными Стратегиями.
31+ */
32+ class Strategy
33+ {
34+ public:
35+ virtual ~Strategy () {}
36+ virtual std::string DoAlgorithm (const std::vector<std::string> &data) const = 0;
37+ };
38+
39+ /* *
40+ * EN: The Context defines the interface of interest to clients.
41+ *
42+ * RU: Контекст определяет интерфейс, представляющий интерес для клиентов.
43+ */
44+
45+ class Context
46+ {
47+ /* *
48+ * EN: @var Strategy The Context maintains a reference to one of the
49+ * Strategy objects. The Context does not know the concrete class of a
50+ * strategy. It should work with all strategies via the Strategy interface.
51+ *
52+ * RU: @var Strategy Контекст хранит ссылку на один из объектов Стратегии.
53+ * Контекст не знает конкретного класса стратегии. Он должен работать со
54+ * всеми стратегиями через интерфейс Стратегии.
55+ */
56+ private:
57+ Strategy *strategy_;
58+ /* *
59+ *
60+ * EN: Usually, the Context accepts a strategy through the constructor, but
61+ * also provides a setter to change it at runtime.
62+ *
63+ * RU: Обычно Контекст принимает стратегию через конструктор, а также
64+ * предоставляет сеттер для её изменения во время выполнения.
65+ */
66+ public:
67+ Context (Strategy *strategy = nullptr ) : strategy_(strategy)
68+ {
69+ }
70+ ~Context ()
71+ {
72+ delete this ->strategy_ ;
73+ }
74+ /* *
75+ * EN: Usually, the Context allows replacing a Strategy object at runtime.
76+ *
77+ * RU: Обычно Контекст позволяет заменить объект Стратегии во время
78+ * выполнения.
79+ */
80+ void set_strategy (Strategy *strategy)
81+ {
82+ delete this ->strategy_ ;
83+ this ->strategy_ = strategy;
84+ }
85+ /* *
86+ * EN: The Context delegates some work to the Strategy object instead of
87+ * implementing +multiple versions of the algorithm on its own.
88+ *
89+ * RU: Вместо того, чтобы самостоятельно реализовывать множественные версии
90+ * алгоритма, Контекст делегирует некоторую работу объекту Стратегии.
91+ */
92+ void DoSomeBusinessLogic () const
93+ {
94+ // ...
95+ std::cout << " Context: Sorting data using the strategy (not sure how it'll do it)\n " ;
96+ std::string result = this ->strategy_ ->DoAlgorithm (std::vector<std::string>{" a" , " e" , " c" , " b" , " d" });
97+ std::cout << result << " \n " ;
98+ // ...
99+ }
100+ };
101+
102+ /* *
103+ * EN: Concrete Strategies implement the algorithm while following the base
104+ * Strategy interface. The interface makes them interchangeable in the Context.
105+ *
106+ * RU: Конкретные Стратегии реализуют алгоритм, следуя базовому интерфейсу
107+ * Стратегии. Этот интерфейс делает их взаимозаменяемыми в Контексте.
108+ */
109+ class ConcreteStrategyA : public Strategy
110+ {
111+ public:
112+ std::string DoAlgorithm (const std::vector<std::string> &data) const override
113+ {
114+ std::string result;
115+ std::for_each (std::begin (data), std::end (data), [&result](const std::string &letter) {
116+ result += letter;
117+ });
118+ std::sort (std::begin (result), std::end (result));
119+
120+ return result;
121+ }
122+ };
123+ class ConcreteStrategyB : public Strategy
124+ {
125+ std::string DoAlgorithm (const std::vector<std::string> &data) const override
126+ {
127+ std::string result;
128+ std::for_each (std::begin (data), std::end (data), [&result](const std::string &letter) {
129+ result += letter;
130+ });
131+ std::sort (std::begin (result), std::end (result));
132+ for (int i = 0 ; i < result.size () / 2 ; i++)
133+ {
134+ std::swap (result[i], result[result.size () - i - 1 ]);
135+ }
136+
137+ return result;
138+ }
139+ };
140+ /* *
141+ * EN: The client code picks a concrete strategy and passes it to the context.
142+ * The client should be aware of the differences between strategies in order to
143+ * make the right choice.
144+ *
145+ * RU: Клиентский код выбирает конкретную стратегию и передаёт её в контекст.
146+ * Клиент должен знать о различиях между стратегиями, чтобы сделать правильный
147+ * выбор.
148+ */
149+
150+ void ClientCode ()
151+ {
152+ Context *context = new Context (new ConcreteStrategyA);
153+ std::cout << " Client: Strategy is set to normal sorting.\n " ;
154+ context->DoSomeBusinessLogic ();
155+ std::cout << " \n " ;
156+ std::cout << " Client: Strategy is set to reverse sorting.\n " ;
157+ context->set_strategy (new ConcreteStrategyB);
158+ context->DoSomeBusinessLogic ();
159+ delete context;
160+ }
161+
162+ int main ()
163+ {
164+ ClientCode ();
165+ return 0 ;
166+ }
0 commit comments