1//! @file apply_design_pattern.hpp
2//! @author ryftchen
3//! @brief The declarations (apply_design_pattern) in the application module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#pragma once
8
9#include "design_pattern/include/behavioral.hpp"
10#include "design_pattern/include/creational.hpp"
11#include "design_pattern/include/structural.hpp"
12
13//! @brief The application module.
14namespace application // NOLINT(modernize-concat-nested-namespaces)
15{
16//! @brief Design-pattern-applying-related functions in the application module.
17namespace app_dp
18{
19//! @brief Apply behavioral.
20namespace behavioral
21{
22//! @brief The version used to apply.
23const char* const version = design_pattern::behavioral::version();
24
25//! @brief Showcase for behavioral instances.
26class Showcase
27{
28public:
29 // NOLINTBEGIN(google-build-using-namespace)
30 //! @brief Chain of responsibility.
31 //! @return procedure output
32 static std::ostringstream chainOfResponsibility()
33 {
34 using namespace design_pattern::behavioral::chain_of_responsibility;
35 const std::shared_ptr<ConcreteHandler1> handler1 = std::make_shared<ConcreteHandler1>();
36 const std::shared_ptr<ConcreteHandler2> handler2 = std::make_shared<ConcreteHandler2>();
37
38 handler1->setHandler(handler2);
39 handler1->handleRequest();
40 return transferOutputs(outputs&: output());
41 }
42 //! @brief Command.
43 //! @return procedure output
44 static std::ostringstream command()
45 {
46 using namespace design_pattern::behavioral::command;
47 const std::shared_ptr<ConcreteCommand> cmd = std::make_shared<ConcreteCommand>(args: std::make_shared<Receiver>());
48
49 Invoker invoker{};
50 invoker.set(cmd);
51 invoker.confirm();
52 return transferOutputs(outputs&: output());
53 }
54 //! @brief Interpreter.
55 //! @return procedure output
56 static std::ostringstream interpreter()
57 {
58 using namespace design_pattern::behavioral::interpreter;
59 const std::shared_ptr<AbstractExpression> a = std::make_shared<TerminalExpression>(args: "A");
60 const std::shared_ptr<AbstractExpression> b = std::make_shared<TerminalExpression>(args: "B");
61 const std::shared_ptr<AbstractExpression> exp = std::make_shared<NonTerminalExpression>(args: a, args: b);
62
63 const std::shared_ptr<Context> context = std::make_shared<Context>();
64 context->set(expr: "A", val: true);
65 context->set(expr: "B", val: false);
66
67 output() << context->get(expr: "A") << " AND " << context->get(expr: "B");
68 output() << " = " << exp->interpret(context) << '\n';
69 return transferOutputs(outputs&: output());
70 }
71 //! @brief Iterator.
72 //! @return procedure output
73 static std::ostringstream iterator()
74 {
75 using namespace design_pattern::behavioral::iterator;
76 constexpr std::uint32_t size = 5;
77 const std::shared_ptr<ConcreteAggregate> list = std::make_shared<ConcreteAggregate>(args: size);
78
79 for (const std::shared_ptr<Iterator> iter = list->createIterator(); !iter->isDone(); iter->next())
80 {
81 output() << "item value: " << iter->currentItem() << '\n';
82 }
83 return transferOutputs(outputs&: output());
84 }
85 //! @brief Mediator.
86 //! @return procedure output
87 static std::ostringstream mediator()
88 {
89 using namespace design_pattern::behavioral::mediator;
90 constexpr std::uint32_t id1 = 1;
91 constexpr std::uint32_t id2 = 2;
92 constexpr std::uint32_t id3 = 3;
93 const std::shared_ptr<Mediator> mediators = std::make_shared<ConcreteMediator>();
94 const std::shared_ptr<Colleague> c1 = std::make_shared<ConcreteColleague>(args: mediators, args: id1);
95 const std::shared_ptr<Colleague> c2 = std::make_shared<ConcreteColleague>(args: mediators, args: id2);
96 const std::shared_ptr<Colleague> c3 = std::make_shared<ConcreteColleague>(args: mediators, args: id3);
97
98 mediators->add(colleague: c1);
99 mediators->add(colleague: c2);
100 mediators->add(colleague: c3);
101 c1->send(msg: "hi!");
102 c3->send(msg: "hello!");
103 return transferOutputs(outputs&: output());
104 }
105 //! @brief Memento.
106 //! @return procedure output
107 static std::ostringstream memento()
108 {
109 using namespace design_pattern::behavioral::memento;
110 constexpr int state1 = 1;
111 constexpr int state2 = 2;
112 constexpr int state3 = 3;
113 const std::shared_ptr<Originator> originator = std::make_shared<Originator>();
114 const std::shared_ptr<CareTaker> caretaker = std::make_shared<CareTaker>(args: originator);
115
116 originator->setState(state1);
117 caretaker->save();
118 originator->setState(state2);
119 caretaker->save();
120 originator->setState(state3);
121 caretaker->undo();
122
123 output() << "actual state is " << originator->getState() << '\n';
124 return transferOutputs(outputs&: output());
125 }
126 //! @brief Observer.
127 //! @return procedure output
128 static std::ostringstream observer()
129 {
130 using namespace design_pattern::behavioral::observer;
131 constexpr int state1 = 1;
132 constexpr int state2 = 2;
133 constexpr int state3 = 3;
134 const std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>(args: state1);
135 const std::shared_ptr<ConcreteObserver> observer2 = std::make_shared<ConcreteObserver>(args: state2);
136
137 output() << "observer1 state: " << observer1->getState() << '\n';
138 output() << "observer2 state: " << observer2->getState() << '\n';
139
140 const std::shared_ptr<Subject> subject = std::make_shared<ConcreteSubject>();
141 subject->attach(observer: observer1);
142 subject->attach(observer: observer2);
143 subject->setState(state3);
144 subject->notify();
145
146 output() << "observer1 state: " << observer1->getState() << '\n';
147 output() << "observer2 state: " << observer2->getState() << '\n';
148 return transferOutputs(outputs&: output());
149 }
150 //! @brief State.
151 //! @return procedure output
152 static std::ostringstream state()
153 {
154 using namespace design_pattern::behavioral::state;
155 const std::shared_ptr<Context> context = std::make_shared<Context>();
156
157 context->setState(std::make_unique<ConcreteStateA>());
158 context->request();
159
160 context->setState(std::make_unique<ConcreteStateB>());
161 context->request();
162 return transferOutputs(outputs&: output());
163 }
164 //! @brief Strategy.
165 //! @return procedure output
166 static std::ostringstream strategy()
167 {
168 using namespace design_pattern::behavioral::strategy;
169 Context contextA(std::make_unique<ConcreteStrategyA>());
170 contextA.contextInterface();
171
172 Context contextB(std::make_unique<ConcreteStrategyB>());
173 contextB.contextInterface();
174 return transferOutputs(outputs&: output());
175 }
176 //! @brief Template method.
177 //! @return procedure output
178 static std::ostringstream templateMethod()
179 {
180 using namespace design_pattern::behavioral::template_method;
181 const std::shared_ptr<AbstractClass> tm = std::make_shared<ConcreteClass>();
182
183 tm->templateMethod();
184 return transferOutputs(outputs&: output());
185 }
186 //! @brief Visitor.
187 //! @return procedure output
188 static std::ostringstream visitor()
189 {
190 using namespace design_pattern::behavioral::visitor;
191 const std::shared_ptr<ConcreteElementA> elementA = std::make_shared<ConcreteElementA>();
192 const std::shared_ptr<ConcreteElementB> elementB = std::make_shared<ConcreteElementB>();
193
194 ConcreteVisitor1 visitor1{};
195 ConcreteVisitor2 visitor2{};
196 elementA->accept(visitor&: visitor1);
197 elementA->accept(visitor&: visitor2);
198 elementB->accept(visitor&: visitor1);
199 elementB->accept(visitor&: visitor2);
200 return transferOutputs(outputs&: output());
201 }
202 // NOLINTEND(google-build-using-namespace)
203
204private:
205 //! @brief Transfer full outputs.
206 //! @param outputs - original outputs
207 //! @return full outputs
208 static std::ostringstream transferOutputs(std::ostringstream& outputs)
209 {
210 std::ostringstream process(outputs.str());
211 outputs.str(s: "");
212 outputs.clear();
213 return process;
214 }
215};
216} // namespace behavioral
217extern void applyingBehavioral(const std::vector<std::string>& candidates);
218
219//! @brief Apply creational.
220namespace creational
221{
222//! @brief The version used to apply.
223const char* const version = design_pattern::creational::version();
224
225//! @brief Showcase for creational instances.
226class Showcase
227{
228public:
229 // NOLINTBEGIN(google-build-using-namespace)
230 //! @brief Abstract factory.
231 //! @return procedure output
232 static std::ostringstream abstractFactory()
233 {
234 using namespace design_pattern::creational::abstract_factory;
235 const std::shared_ptr<ConcreteFactoryX> factoryX = std::make_shared<ConcreteFactoryX>();
236 const std::shared_ptr<ConcreteFactoryY> factoryY = std::make_shared<ConcreteFactoryY>();
237
238 const std::unique_ptr<ProductA> p1 = factoryX->createProductA();
239 output() << "product: " << p1->getName() << '\n';
240
241 const std::unique_ptr<ProductA> p2 = factoryY->createProductA();
242 output() << "product: " << p2->getName() << '\n';
243
244 const std::unique_ptr<ProductB> p3 = factoryX->createProductB();
245 output() << "product: " << p3->getName() << '\n';
246
247 const std::unique_ptr<ProductB> p4 = factoryY->createProductB();
248 output() << "product: " << p4->getName() << '\n';
249 return transferOutputs(outputs&: output());
250 }
251 //! @brief Builder.
252 //! @return procedure output
253 static std::ostringstream builder()
254 {
255 using namespace design_pattern::creational::builder;
256 Director director{};
257 director.set(std::make_unique<ConcreteBuilderX>());
258 director.construct();
259 const Product product1 = director.get();
260 output() << "1st product parts: " << product1.get() << '\n';
261
262 director.set(std::make_unique<ConcreteBuilderY>());
263 director.construct();
264 const Product product2 = director.get();
265 output() << "2nd product parts: " << product2.get() << '\n';
266 return transferOutputs(outputs&: output());
267 }
268 //! @brief Factory method.
269 //! @return procedure output
270 static std::ostringstream factoryMethod()
271 {
272 using namespace design_pattern::creational::factory_method;
273 const std::shared_ptr<Creator> creator = std::make_shared<ConcreteCreator>();
274
275 std::unique_ptr<Product> p1 = creator->createProductA();
276 output() << "product: " << p1->getName() << '\n';
277 creator->removeProduct(product&: p1);
278
279 std::unique_ptr<Product> p2 = creator->createProductB();
280 output() << "product: " << p2->getName() << '\n';
281 creator->removeProduct(product&: p2);
282 return transferOutputs(outputs&: output());
283 }
284 //! @brief Prototype.
285 //! @return procedure output
286 static std::ostringstream prototype()
287 {
288 using namespace design_pattern::creational::prototype;
289 Client::init();
290
291 const std::unique_ptr<Prototype> prototype1 = Client::make(index: 0);
292 output() << "prototype: " << prototype1->type() << '\n';
293
294 const std::unique_ptr<Prototype> prototype2 = Client::make(index: 1);
295 output() << "prototype: " << prototype2->type() << '\n';
296
297 Client::remove();
298 return transferOutputs(outputs&: output());
299 }
300 //! @brief Singleton.
301 //! @return procedure output
302 static std::ostringstream singleton()
303 {
304 using namespace design_pattern::creational::singleton;
305 Singleton::get()->tell();
306
307 Singleton::restart();
308 return transferOutputs(outputs&: output());
309 }
310 // NOLINTEND(google-build-using-namespace)
311
312private:
313 //! @brief Transfer full outputs.
314 //! @param outputs - original outputs
315 //! @return full outputs
316 static std::ostringstream transferOutputs(std::ostringstream& outputs)
317 {
318 std::ostringstream process(outputs.str());
319 outputs.str(s: "");
320 outputs.clear();
321 return process;
322 }
323};
324} // namespace creational
325extern void applyingCreational(const std::vector<std::string>& candidates);
326
327//! @brief Apply structural.
328namespace structural
329{
330//! @brief The version used to apply.
331const char* const version = design_pattern::structural::version();
332
333//! @brief Showcase for structural instances.
334class Showcase
335{
336public:
337 // NOLINTBEGIN(google-build-using-namespace)
338 //! @brief Adapter.
339 //! @return procedure output
340 static std::ostringstream adapter()
341 {
342 using namespace design_pattern::structural::adapter;
343 const std::shared_ptr<Target> adp = std::make_shared<Adapter>();
344
345 adp->request();
346 return transferOutputs(outputs&: output());
347 }
348 //! @brief Bridge.
349 //! @return procedure output
350 static std::ostringstream bridge()
351 {
352 using namespace design_pattern::structural::bridge;
353 const std::unique_ptr<Abstraction> abstract1 =
354 std::make_unique<RefinedAbstraction>(args: std::make_unique<ConcreteImplementorA>());
355 abstract1->operation();
356
357 const std::unique_ptr<Abstraction> abstract2 =
358 std::make_unique<RefinedAbstraction>(args: std::make_unique<ConcreteImplementorB>());
359 abstract2->operation();
360 return transferOutputs(outputs&: output());
361 }
362 //! @brief Composite.
363 //! @return procedure output
364 static std::ostringstream composite()
365 {
366 using namespace design_pattern::structural::composite;
367 constexpr std::uint32_t count = 5;
368 Composite composites{};
369
370 for (std::uint32_t i = 0; i < count; ++i)
371 {
372 composites.add(component: std::make_shared<Leaf>(args&: i));
373 }
374 composites.remove(index: 0);
375 composites.operation();
376 return transferOutputs(outputs&: output());
377 }
378 //! @brief Decorator.
379 //! @return procedure output
380 static std::ostringstream decorator()
381 {
382 using namespace design_pattern::structural::decorator;
383 const std::shared_ptr<ConcreteComponent> cc = std::make_shared<ConcreteComponent>();
384 const std::shared_ptr<ConcreteDecoratorA> da = std::make_shared<ConcreteDecoratorA>(args: cc);
385 const std::shared_ptr<ConcreteDecoratorB> db = std::make_shared<ConcreteDecoratorB>(args: da);
386
387 const std::shared_ptr<Component> component = db;
388 component->operation();
389 return transferOutputs(outputs&: output());
390 }
391 //! @brief Facade.
392 //! @return procedure output
393 static std::ostringstream facade()
394 {
395 using namespace design_pattern::structural::facade;
396 const std::shared_ptr<Facade> facades = std::make_shared<Facade>();
397
398 facades->operation1();
399 facades->operation2();
400 return transferOutputs(outputs&: output());
401 }
402 //! @brief Flyweight.
403 //! @return procedure output
404 static std::ostringstream flyweight()
405 {
406 using namespace design_pattern::structural::flyweight;
407 const std::shared_ptr<FlyweightFactory> factory = std::make_shared<FlyweightFactory>();
408
409 factory->getFlyweight(key: 1)->operation();
410 factory->getFlyweight(key: 2)->operation();
411 return transferOutputs(outputs&: output());
412 }
413 //! @brief Proxy.
414 //! @return procedure output
415 static std::ostringstream proxy()
416 {
417 using namespace design_pattern::structural::proxy;
418 const std::shared_ptr<Proxy> proxies = std::make_shared<Proxy>();
419
420 proxies->request();
421 return transferOutputs(outputs&: output());
422 }
423
424private:
425 //! @brief Transfer full outputs.
426 //! @param outputs - original outputs
427 //! @return full outputs
428 static std::ostringstream transferOutputs(std::ostringstream& outputs)
429 {
430 std::ostringstream process(outputs.str());
431 outputs.str(s: "");
432 outputs.clear();
433 return process;
434 }
435 // NOLINTEND(google-build-using-namespace)
436};
437} // namespace structural
438extern void applyingStructural(const std::vector<std::string>& candidates);
439} // namespace app_dp
440} // namespace application
441