diff --git a/CMakeLists.txt b/CMakeLists.txt
index 222f90c..8e974cb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,6 +99,7 @@ set(APP_SOURCES
"src/patterns/structural/Facade.cpp"
"src/patterns/structural/Decorator.cpp"
"src/patterns/behavioral/ChainOfCommand.cpp"
+ "src/patterns/behavioral/Command.cpp"
)
# Test files
diff --git a/docs/uml/patterns_behavioral_command.drawio.svg b/docs/uml/patterns_behavioral_command.drawio.svg
new file mode 100644
index 0000000..26151c5
--- /dev/null
+++ b/docs/uml/patterns_behavioral_command.drawio.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/patterns/behavioral/ChainOfCommand.cpp b/src/patterns/behavioral/ChainOfCommand.cpp
index 7331adc..5d52c1f 100644
--- a/src/patterns/behavioral/ChainOfCommand.cpp
+++ b/src/patterns/behavioral/ChainOfCommand.cpp
@@ -16,6 +16,9 @@ namespace
{
namespace CoR
{
+ /*
+ * Handler - defines an interface for handling requests
+ */
class IHandler
{
public:
@@ -57,6 +60,10 @@ namespace
}
};
+ /**
+ * CoreteHandlers - handles the requests it is responsible for
+ * If it can handle the request it does so, otherwise it sends the request to its successor
+ */
class ConcreteHandlerGET : public AbstractHandler
{
private:
@@ -116,6 +123,9 @@ namespace
}
};
+ /**
+ * Client - sends commands to the first object in the chain that may handle the command
+ */
namespace Client
{
void clientCode(IHandler &handler, const std::string &request)
@@ -155,6 +165,7 @@ struct CoRAutoRunner
{
CoRAutoRunner()
{
+ std::cout << "\n--- CoR Pattern Example ---\n";
CoR::run();
}
};
diff --git a/src/patterns/behavioral/Command.cpp b/src/patterns/behavioral/Command.cpp
new file mode 100644
index 0000000..b2bbe22
--- /dev/null
+++ b/src/patterns/behavioral/Command.cpp
@@ -0,0 +1,162 @@
+// Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. (receivers, payloads)
+// This transformation lets you pass requests as a method arguments, delay or queue a request’s execution, and support undoable operations.
+// Allows an object to send a command without knowing what object will receive and handle it.
+// Appicability:
+// (*) when you want to parameterize objects with operations.
+// (**) when you want to queue operations, schedule their execution, or execute them remotely.
+// (***) when you want to implement reversible operations.
+
+// UML: docs/uml/patterns_behavioral_command.drawio.svg
+
+#include
+#include
+
+namespace
+{
+ namespace Command
+ {
+
+ /**
+ * The Command interface usually declares just a single method for executing the command.
+ * e.g. Save, Undo, Jump, Backup, CreateOrder
+ */
+ class ICommand
+ {
+ public:
+ virtual void execute() const = 0;
+ };
+
+ /**
+ * The Receiver class contains some business logic. Almost any object may act as a receiver.
+ * Most commands only handle the details of how a request is passed to the receiver, while the receiver itself does the actual work.
+ * e.g. Document, GameCharacter, DB service
+ */
+ class Receiver
+ {
+ public:
+ static void doCheck()
+ {
+ std::cout << "Receiver checking... \n";
+ };
+ static void doInit()
+ {
+ std::cout << "Receiver initializing... \n";
+ };
+ static void doLaunch(const std::string &arg)
+ {
+ std::cout << "Receiver launching... \n\t" << arg << "\n";
+ };
+ };
+
+ /**
+ * Concrete Commands implement various kinds of requests.
+ * 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.
+ * However, for the sake of simplifying the code, these classes can be merged.
+ */
+ class SimpleConcreteCommand : public ICommand
+ {
+ public:
+ void execute() const override
+ {
+ std::cout << "\t SimpleCommand executed \n";
+ }
+ };
+
+ class ComplexConcreteCommand : public ICommand
+ {
+ private:
+ Receiver *m_receiver;
+ std::string m_payload;
+
+ public:
+ ComplexConcreteCommand(Receiver *receiver, const std::string &payload) : m_receiver{receiver}, m_payload{payload} {};
+
+ void execute() const override
+ {
+ std::cout << "\t ComplexCommand executed \n";
+ this->m_receiver->doCheck();
+ this->m_receiver->doInit();
+ this->m_receiver->doLaunch(m_payload);
+ }
+ };
+
+ /**
+ *The Sender class (aka invoker) is responsible for initiating requests.
+ *This class must have a field for storing a reference to a command object.
+ *The sender triggers that command instead of sending the request directly to the receiver.
+ *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.
+ *e.g. Button, Shortcut, Scheduler, Event bus...
+ */
+ class Invoker
+ {
+ private:
+ ICommand *m_on_start;
+ ICommand *m_on_finish;
+
+ public:
+ explicit Invoker(ICommand *s = nullptr, ICommand *f = nullptr) : m_on_start{s}, m_on_finish{s}
+ {
+ }
+
+ ~Invoker()
+ {
+ delete m_on_start;
+ delete m_on_finish;
+ }
+
+ void setOnStart(ICommand *command)
+ {
+ this->m_on_start = command;
+ }
+
+ void setOnFinish(ICommand *command)
+ {
+ this->m_on_finish = command;
+ }
+
+ void invoke() const
+ {
+ if (m_on_start != nullptr)
+ {
+ m_on_start->execute();
+ }
+
+ if (m_on_finish != nullptr)
+ {
+ m_on_finish->execute();
+ }
+ }
+ };
+
+ namespace Client
+ {
+ void clientCode(const Invoker *invoker)
+ {
+ invoker->invoke();
+ }
+
+ }
+
+ void run()
+ {
+ Receiver *ui = new Receiver();
+ // How to execute these command when something triggered
+ Invoker *invoker = new Invoker();
+ invoker->setOnStart(new SimpleConcreteCommand());
+ invoker->setOnFinish(new ComplexConcreteCommand(ui, "cmd --version"));
+ Client::clientCode(invoker);
+ delete ui;
+ }
+ }
+}
+
+struct CommandAutoRunner
+{
+ CommandAutoRunner()
+ {
+ std::cout << "\n--- Command Pattern Example ---\n";
+ Command::run();
+ }
+};
+
+static CommandAutoRunner instance;
\ No newline at end of file