1//! @file behavioral.cpp
2//! @author ryftchen
3//! @brief The definitions (behavioral) in the data structure module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved.
6
7#include "behavioral.hpp"
8
9#include <algorithm>
10#include <iomanip>
11
12namespace design_pattern::behavioral
13{
14//! @brief Function version number.
15//! @return version number (major.minor.patch)
16const char* version() noexcept
17{
18 static const char* const ver = "0.1.0";
19 return ver;
20}
21
22namespace chain_of_responsibility
23{
24void Handler::setHandler(std::shared_ptr<Handler> handler)
25{
26 successor = std::move(handler);
27}
28
29void Handler::handleRequest()
30{
31 if (successor)
32 {
33 successor->handleRequest();
34 }
35}
36
37bool ConcreteHandler1::canHandle()
38{
39 return false;
40}
41
42void ConcreteHandler1::handleRequest()
43{
44 if (canHandle())
45 {
46 output() << "handled by concrete handler 1\n";
47 }
48 else
49 {
50 output() << "cannot be handled by handler 1\n";
51 Handler::handleRequest();
52 }
53}
54
55bool ConcreteHandler2::canHandle()
56{
57 return true;
58}
59
60void ConcreteHandler2::handleRequest()
61{
62 if (canHandle())
63 {
64 output() << "handled by handler 2\n";
65 }
66 else
67 {
68 output() << "cannot be handled by handler 2\n";
69 Handler::handleRequest();
70 }
71}
72
73//! @brief Output stream for the chain of responsibility pattern. Need to be cleared manually.
74//! @return reference of the output stream object, which is on string based
75std::ostringstream& output() noexcept
76{
77 static std::ostringstream process{};
78 return process;
79}
80} // namespace chain_of_responsibility
81
82namespace command
83{
84void Receiver::action()
85{
86 output() << "receiver: execute action\n";
87}
88
89void ConcreteCommand::execute()
90{
91 receiver.lock()->action();
92}
93
94void Invoker::set(const std::shared_ptr<Command>& c)
95{
96 command = c;
97}
98
99void Invoker::confirm()
100{
101 if (const auto c = command.lock())
102 {
103 c->execute();
104 }
105}
106
107//! @brief Output stream for the command pattern. Need to be cleared manually.
108//! @return reference of the output stream object, which is on string based
109std::ostringstream& output() noexcept
110{
111 static std::ostringstream process{};
112 return process;
113}
114} // namespace command
115
116namespace interpreter
117{
118void Context::set(const std::string& expr, const bool val)
119{
120 vars.emplace(args: expr, args: val);
121}
122
123bool Context::get(const std::string& expr)
124{
125 return vars.at(k: expr);
126}
127
128bool AbstractExpression::interpret(const std::shared_ptr<Context>& /*context*/)
129{
130 return false;
131}
132
133bool TerminalExpression::interpret(const std::shared_ptr<Context>& context)
134{
135 return context->get(expr: value);
136}
137
138bool NonTerminalExpression::interpret(const std::shared_ptr<Context>& context)
139{
140 return leftOp->interpret(context) && rightOp->interpret(context);
141}
142
143//! @brief Output stream for the interpreter pattern. Need to be cleared manually.
144//! @return reference of the output stream object, which is on string based
145std::ostringstream& output() noexcept
146{
147 static std::ostringstream process{};
148 return process;
149}
150} // namespace interpreter
151
152namespace iterator
153{
154ConcreteAggregate::ConcreteAggregate(const std::uint32_t size) : count{size}
155{
156 list = std::make_unique<int[]>(num: size);
157 std::fill_n(first: list.get(), n: size, value: 1);
158}
159
160std::shared_ptr<Iterator> ConcreteAggregate::createIterator()
161{
162 return std::make_shared<ConcreteIterator>(args: shared_from_this());
163}
164
165std::uint32_t ConcreteAggregate::size() const
166{
167 return count;
168}
169
170int ConcreteAggregate::at(const std::uint32_t index)
171{
172 return list[index];
173}
174
175void ConcreteIterator::first()
176{
177 index = 0;
178}
179
180void ConcreteIterator::next()
181{
182 ++index;
183}
184
185bool ConcreteIterator::isDone() const
186{
187 return index >= aggregate->size();
188}
189
190int ConcreteIterator::currentItem() const
191{
192 return isDone() ? -1 : aggregate->at(index);
193}
194
195//! @brief Output stream for the iterator pattern. Need to be cleared manually.
196//! @return reference of the output stream object, which is on string based
197std::ostringstream& output() noexcept
198{
199 static std::ostringstream process{};
200 return process;
201}
202} // namespace iterator
203
204namespace mediator
205{
206void ConcreteMediator::add(const std::shared_ptr<Colleague>& colleague)
207{
208 colleagues.emplace_back(args: colleague);
209}
210
211void ConcreteMediator::distribute(const std::shared_ptr<Colleague>& sender, const std::string_view msg)
212{
213 std::for_each(
214 first: colleagues.cbegin(),
215 last: colleagues.cend(),
216 f: [&sender, &msg](const auto& colleague)
217 {
218 if (const auto c = colleague.lock(); c && (c->getId() != sender->getId()))
219 {
220 c->receive(msg);
221 }
222 });
223}
224
225std::uint32_t Colleague::getId() const
226{
227 return id;
228}
229
230void ConcreteColleague::send(const std::string_view msg)
231{
232 output() << "message " << std::quoted(sv: msg) << " sent by colleague " << id << '\n';
233 mediator.lock()->distribute(sender: shared_from_this(), msg);
234}
235
236void ConcreteColleague::receive(const std::string_view msg)
237{
238 output() << "message " << std::quoted(sv: msg) << " received by colleague " << id << '\n';
239}
240
241//! @brief Output stream for the mediator pattern. Need to be cleared manually.
242//! @return reference of the output stream object, which is on string based
243std::ostringstream& output() noexcept
244{
245 static std::ostringstream process{};
246 return process;
247}
248} // namespace mediator
249
250namespace memento
251{
252void Memento::setState(const int s)
253{
254 state = s;
255}
256
257int Memento::getState() const
258{
259 return state;
260}
261
262void Originator::setState(const int s)
263{
264 output() << "set state to " << s << '\n';
265 state = s;
266}
267
268int Originator::getState() const
269{
270 return state;
271}
272
273void Originator::setMemento(const std::shared_ptr<Memento>& memento)
274{
275 state = memento->getState();
276}
277
278std::shared_ptr<Memento> Originator::createMemento() const
279{
280 return std::shared_ptr<Memento>(::new Memento(state));
281}
282
283void CareTaker::save()
284{
285 output() << "save state\n";
286 history.emplace_back(args: originator->createMemento());
287}
288
289void CareTaker::undo()
290{
291 if (history.empty())
292 {
293 output() << "unable to undo state\n";
294 return;
295 }
296
297 std::shared_ptr<Memento> memento = history.back();
298 originator->setMemento(memento);
299 output() << "undo state\n";
300
301 history.pop_back();
302 memento.reset();
303}
304
305//! @brief Output stream for the memento pattern. Need to be cleared manually.
306//! @return reference of the output stream object, which is on string based
307std::ostringstream& output() noexcept
308{
309 static std::ostringstream process{};
310 return process;
311}
312} // namespace memento
313
314namespace observer
315{
316void Subject::attach(const std::shared_ptr<Observer>& observer)
317{
318 observers.emplace_back(args: observer);
319}
320
321void Subject::detach(const int index)
322{
323 observers.erase(position: observers.cbegin() + index);
324}
325
326void Subject::notify()
327{
328 std::for_each(
329 first: observers.cbegin(),
330 last: observers.cend(),
331 f: [this](const auto& observer)
332 {
333 if (const auto obs = observer.lock())
334 {
335 obs->update(weak_from_this());
336 }
337 });
338}
339
340int ConcreteObserver::getState() const
341{
342 return observerState;
343}
344
345void ConcreteObserver::update(const std::weak_ptr<Subject>& subject)
346{
347 if (const auto sub = subject.lock())
348 {
349 observerState = sub->getState();
350 output() << "observer state updated\n";
351 }
352}
353
354int ConcreteSubject::getState() const
355{
356 return subjectState;
357}
358
359void ConcreteSubject::setState(const int s)
360{
361 subjectState = s;
362}
363
364//! @brief Output stream for the observer pattern. Need to be cleared manually.
365//! @return reference of the output stream object, which is on string based
366std::ostringstream& output() noexcept
367{
368 static std::ostringstream process{};
369 return process;
370}
371} // namespace observer
372
373namespace state
374{
375void ConcreteStateA::handle()
376{
377 output() << "state A handled\n";
378}
379
380void ConcreteStateB::handle()
381{
382 output() << "state B handled\n";
383}
384
385void Context::setState(std::unique_ptr<State> s)
386{
387 state = std::move(s);
388}
389
390void Context::request()
391{
392 state->handle();
393}
394
395//! @brief Output stream for the state pattern. Need to be cleared manually.
396//! @return reference of the output stream object, which is on string based
397std::ostringstream& output() noexcept
398{
399 static std::ostringstream process{};
400 return process;
401}
402} // namespace state
403
404namespace strategy
405{
406void ConcreteStrategyA::algorithmInterface()
407{
408 output() << "concrete strategy A\n";
409}
410
411void ConcreteStrategyB::algorithmInterface()
412{
413 output() << "concrete strategy B\n";
414}
415
416void Context::contextInterface()
417{
418 strategy->algorithmInterface();
419}
420
421//! @brief Output stream for the strategy pattern. Need to be cleared manually.
422//! @return reference of the output stream object, which is on string based
423std::ostringstream& output() noexcept
424{
425 static std::ostringstream process{};
426 return process;
427}
428} // namespace strategy
429
430namespace template_method
431{
432void AbstractClass::templateMethod()
433{
434 primitiveOperation1();
435 primitiveOperation2();
436}
437
438void ConcreteClass::primitiveOperation1()
439{
440 output() << "primitive operation 1\n";
441}
442
443void ConcreteClass::primitiveOperation2()
444{
445 output() << "primitive operation 2\n";
446}
447
448//! @brief Output stream for the template method pattern. Need to be cleared manually.
449//! @return reference of the output stream object, which is on string based
450std::ostringstream& output() noexcept
451{
452 static std::ostringstream process{};
453 return process;
454}
455} // namespace template_method
456
457namespace visitor
458{
459void ConcreteVisitor1::visitElementA(const std::shared_ptr<ConcreteElementA>& /*element*/)
460{
461 output() << "concrete visitor 1: element A visited\n";
462}
463
464void ConcreteVisitor1::visitElementB(const std::shared_ptr<ConcreteElementB>& /*element*/)
465{
466 output() << "concrete visitor 1: element B visited\n";
467}
468
469void ConcreteVisitor2::visitElementA(const std::shared_ptr<ConcreteElementA>& /*element*/)
470{
471 output() << "concrete visitor 2: element A visited\n";
472}
473
474void ConcreteVisitor2::visitElementB(const std::shared_ptr<ConcreteElementB>& /*element*/)
475{
476 output() << "concrete visitor 2: element B visited\n";
477}
478
479void ConcreteElementA::accept(Visitor& visitor)
480{
481 visitor.visitElementA(element: shared_from_this());
482}
483
484void ConcreteElementB::accept(Visitor& visitor)
485{
486 visitor.visitElementB(element: shared_from_this());
487}
488
489//! @brief Output stream for the visitor pattern. Need to be cleared manually.
490//! @return reference of the output stream object, which is on string based
491std::ostringstream& output() noexcept
492{
493 static std::ostringstream process{};
494 return process;
495}
496} // namespace visitor
497} // namespace design_pattern::behavioral
498