1+ // Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. (receivers, payloads)
2+ // This transformation lets you pass requests as a method arguments, delay or queue a request’s execution, and support undoable operations.
3+ // Allows an object to send a command without knowing what object will receive and handle it.
4+ // Appicability:
5+ // (*) when you want to parameterize objects with operations.
6+ // (**) when you want to queue operations, schedule their execution, or execute them remotely.
7+ // (***) when you want to implement reversible operations.
8+
9+ // UML: docs/uml/patterns_behavioral_command.drawio.svg
10+
11+ #include < iostream>
12+ #include < string>
13+
14+ namespace
15+ {
16+ namespace Command
17+ {
18+
19+ /* *
20+ * The Command interface usually declares just a single method for executing the command.
21+ * e.g. Save, Undo, Jump, Backup, CreateOrder
22+ */
23+ class ICommand
24+ {
25+ public:
26+ virtual void execute () const = 0;
27+ };
28+
29+ /* *
30+ * The Receiver class contains some business logic. Almost any object may act as a receiver.
31+ * Most commands only handle the details of how a request is passed to the receiver, while the receiver itself does the actual work.
32+ * e.g. Document, GameCharacter, DB service
33+ */
34+ class Receiver
35+ {
36+ public:
37+ static void doCheck ()
38+ {
39+ std::cout << " Receiver checking... \n " ;
40+ };
41+ static void doInit ()
42+ {
43+ std::cout << " Receiver initializing... \n " ;
44+ };
45+ static void doLaunch (const std::string &arg)
46+ {
47+ std::cout << " Receiver launching... \n\t " << arg << " \n " ;
48+ };
49+ };
50+
51+ /* *
52+ * Concrete Commands implement various kinds of requests.
53+ * A concrete command isn’t supposed to perform the work on its own, but rather to pass the call to one of the business logic objects.
54+ * However, for the sake of simplifying the code, these classes can be merged.
55+ */
56+ class SimpleConcreteCommand : public ICommand
57+ {
58+ public:
59+ void execute () const override
60+ {
61+ std::cout << " \t SimpleCommand executed \n " ;
62+ }
63+ };
64+
65+ class ComplexConcreteCommand : public ICommand
66+ {
67+ private:
68+ Receiver *m_receiver;
69+ std::string m_payload;
70+
71+ public:
72+ ComplexConcreteCommand (Receiver *receiver, const std::string &payload) : m_receiver{receiver}, m_payload{payload} {};
73+
74+ void execute () const override
75+ {
76+ std::cout << " \t ComplexCommand executed \n " ;
77+ this ->m_receiver ->doCheck ();
78+ this ->m_receiver ->doInit ();
79+ this ->m_receiver ->doLaunch (m_payload);
80+ }
81+ };
82+
83+ /* *
84+ *The Sender class (aka invoker) is responsible for initiating requests.
85+ *This class must have a field for storing a reference to a command object.
86+ *The sender triggers that command instead of sending the request directly to the receiver.
87+ *Note that the sender isn’t responsible for creating the command object. Usually, it gets a pre-created command from the client via the constructor.
88+ *e.g. Button, Shortcut, Scheduler, Event bus...
89+ */
90+ class Invoker
91+ {
92+ private:
93+ ICommand *m_on_start;
94+ ICommand *m_on_finish;
95+
96+ public:
97+ explicit Invoker (ICommand *s = nullptr , ICommand *f = nullptr ) : m_on_start{s}, m_on_finish{s}
98+ {
99+ }
100+
101+ ~Invoker ()
102+ {
103+ delete m_on_start;
104+ delete m_on_finish;
105+ }
106+
107+ void setOnStart (ICommand *command)
108+ {
109+ this ->m_on_start = command;
110+ }
111+
112+ void setOnFinish (ICommand *command)
113+ {
114+ this ->m_on_finish = command;
115+ }
116+
117+ void invoke () const
118+ {
119+ if (m_on_start != nullptr )
120+ {
121+ m_on_start->execute ();
122+ }
123+
124+ if (m_on_finish != nullptr )
125+ {
126+ m_on_finish->execute ();
127+ }
128+ }
129+ };
130+
131+ namespace Client
132+ {
133+ void clientCode (const Invoker *invoker)
134+ {
135+ invoker->invoke ();
136+ }
137+
138+ }
139+
140+ void run ()
141+ {
142+ Receiver *ui = new Receiver ();
143+ // How to execute these command when something triggered
144+ Invoker *invoker = new Invoker ();
145+ invoker->setOnStart (new SimpleConcreteCommand ());
146+ invoker->setOnFinish (new ComplexConcreteCommand (ui, " cmd --version" ));
147+ Client::clientCode (invoker);
148+ delete ui;
149+ }
150+ }
151+ }
152+
153+ struct CommandAutoRunner
154+ {
155+ CommandAutoRunner ()
156+ {
157+ std::cout << " \n --- Command Pattern Example ---\n " ;
158+ Command::run ();
159+ }
160+ };
161+
162+ static CommandAutoRunner instance;
0 commit comments