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: ";
293 if (prototype1)
294 {
295 output() << prototype1->type();
296 }
297 else
298 {
299 output() << "<null>";
300 }
301 output() << '\n';
302
303 const std::unique_ptr<Prototype> prototype2 = Client::make(index: 1);
304 output() << "prototype: ";
305 if (prototype2)
306 {
307 output() << prototype2->type();
308 }
309 else
310 {
311 output() << "<null>";
312 }
313 output() << '\n';
314
315 Client::remove();
316 return transferOutputs(outputs&: output());
317 }
318 //! @brief Singleton.
319 //! @return procedure output
320 static std::ostringstream singleton()
321 {
322 using namespace design_pattern::creational::singleton;
323 Singleton::get()->tell();
324
325 Singleton::restart();
326 return transferOutputs(outputs&: output());
327 }
328 // NOLINTEND(google-build-using-namespace)
329
330private:
331 //! @brief Transfer full outputs.
332 //! @param outputs - original outputs
333 //! @return full outputs
334 static std::ostringstream transferOutputs(std::ostringstream& outputs)
335 {
336 std::ostringstream process(outputs.str());
337 outputs.str(s: "");
338 outputs.clear();
339 return process;
340 }
341};
342} // namespace creational
343extern void applyingCreational(const std::vector<std::string>& candidates);
344
345//! @brief Apply structural.
346namespace structural
347{
348//! @brief The version used to apply.
349const char* const version = design_pattern::structural::version();
350
351//! @brief Showcase for structural instances.
352class Showcase
353{
354public:
355 // NOLINTBEGIN(google-build-using-namespace)
356 //! @brief Adapter.
357 //! @return procedure output
358 static std::ostringstream adapter()
359 {
360 using namespace design_pattern::structural::adapter;
361 const std::shared_ptr<Target> adp = std::make_shared<Adapter>();
362
363 adp->request();
364 return transferOutputs(outputs&: output());
365 }
366 //! @brief Bridge.
367 //! @return procedure output
368 static std::ostringstream bridge()
369 {
370 using namespace design_pattern::structural::bridge;
371 const std::unique_ptr<Abstraction> abstract1 =
372 std::make_unique<RefinedAbstraction>(args: std::make_unique<ConcreteImplementorA>());
373 abstract1->operation();
374
375 const std::unique_ptr<Abstraction> abstract2 =
376 std::make_unique<RefinedAbstraction>(args: std::make_unique<ConcreteImplementorB>());
377 abstract2->operation();
378 return transferOutputs(outputs&: output());
379 }
380 //! @brief Composite.
381 //! @return procedure output
382 static std::ostringstream composite()
383 {
384 using namespace design_pattern::structural::composite;
385 constexpr std::uint32_t count = 5;
386 Composite composites{};
387
388 for (std::uint32_t i = 0; i < count; ++i)
389 {
390 composites.add(component: std::make_shared<Leaf>(args&: i));
391 }
392 composites.remove(index: 0);
393 composites.operation();
394 return transferOutputs(outputs&: output());
395 }
396 //! @brief Decorator.
397 //! @return procedure output
398 static std::ostringstream decorator()
399 {
400 using namespace design_pattern::structural::decorator;
401 const std::shared_ptr<ConcreteComponent> cc = std::make_shared<ConcreteComponent>();
402 const std::shared_ptr<ConcreteDecoratorA> da = std::make_shared<ConcreteDecoratorA>(args: cc);
403 const std::shared_ptr<ConcreteDecoratorB> db = std::make_shared<ConcreteDecoratorB>(args: da);
404
405 const std::shared_ptr<Component> component = db;
406 component->operation();
407 return transferOutputs(outputs&: output());
408 }
409 //! @brief Facade.
410 //! @return procedure output
411 static std::ostringstream facade()
412 {
413 using namespace design_pattern::structural::facade;
414 const std::shared_ptr<Facade> facades = std::make_shared<Facade>();
415
416 facades->operation1();
417 facades->operation2();
418 return transferOutputs(outputs&: output());
419 }
420 //! @brief Flyweight.
421 //! @return procedure output
422 static std::ostringstream flyweight()
423 {
424 using namespace design_pattern::structural::flyweight;
425 const std::shared_ptr<FlyweightFactory> factory = std::make_shared<FlyweightFactory>();
426
427 factory->getFlyweight(key: 1)->operation();
428 factory->getFlyweight(key: 2)->operation();
429 return transferOutputs(outputs&: output());
430 }
431 //! @brief Proxy.
432 //! @return procedure output
433 static std::ostringstream proxy()
434 {
435 using namespace design_pattern::structural::proxy;
436 const std::shared_ptr<Proxy> proxies = std::make_shared<Proxy>();
437
438 proxies->request();
439 return transferOutputs(outputs&: output());
440 }
441
442private:
443 //! @brief Transfer full outputs.
444 //! @param outputs - original outputs
445 //! @return full outputs
446 static std::ostringstream transferOutputs(std::ostringstream& outputs)
447 {
448 std::ostringstream process(outputs.str());
449 outputs.str(s: "");
450 outputs.clear();
451 return process;
452 }
453 // NOLINTEND(google-build-using-namespace)
454};
455} // namespace structural
456extern void applyingStructural(const std::vector<std::string>& candidates);
457} // namespace app_dp
458} // namespace application
459