Command – behavioral design pattern – library MetaTrader 5

//+------------------------------------------------------------------+
//|                                                      Command.mqh |
//|                                    2019-2020, dimitri pecheritsa |
//|                                                 792112@gmail.com |
//+------------------------------------------------------------------+
//| command — behavioral design pattern                              |
//+------------------------------------------------------------------+
//   design patterns: elements of reusable object-oriented software
//   gof > erich gamma, richard helm, ralph johnson, john vlissides
//   published — 1994
//+------------------------------------------------------------------+
//| intent                                                           |
//+------------------------------------------------------------------+
//   encapsulate a request as an object
//    thereby letting you parameterize clients with different requests
//   queue or log requests, and support undoable operations
//+------------------------------------------------------------------+
//| benefits                                                         |
//+------------------------------------------------------------------+
//   variable aspect > when and how a request is fulfilled
//   refactoring
//      problems
//         dependence on specific operations
//         tight coupling
//      solutions
//         avoid hard-coded requests > also > chain of responsibility
//         decouple with abstract coupling and layering
//            also > abstract factory, bridge, chain of responsibility,
//             facade, mediator, observer
//+------------------------------------------------------------------+
//| applicability                                                    |
//+------------------------------------------------------------------+
//   parameterize objects by an action to perform
//   specify, queue, and execute requests at different times
//      command is independent of the original request
//   support undo
//   support change log
//      reapply after a system crash
//      add load/store to command
//      reload from disk
//      reexecute with the execute
//   structure a system around high-level operations
//    built on primitives operations
//+------------------------------------------------------------------+
//| structure                                                        |
//+------------------------------------------------------------------+
//
// |Client|      |Invoker|o------------------->| Command |
//   |  |                                      |---------|
//      |                                      |Execute()|
//   |  +------->|Receiver|                         ^
//               |--------|      receiver           |
//   |           |Action()|<--------------|  ConcreteCommand |
//                                        |------------------|
//   |                                    |Execute()         |
//                                        | receiver.Action()|
//   |                                    |------------------|
//   + - - - - - - - - - - - - - - - - - >|state             |
//
#include <SRCPatternsPatternOrganizer.mqh>
namespace Command
{
//+------------------------------------------------------------------+
//| participants > receiver                                          |
//+------------------------------------------------------------------+
class Receiver
//   knows how to perform the request operations
//   any class may be a receiver
  {
public:
                     Receiver(void);
                     Receiver(Receiver&);
   void              Action(void);
  };
//+------------------------------------------------------------------+
//| participants > receiver > default                                |
//+------------------------------------------------------------------+
Receiver::Receiver(void)
  {
  }
//+------------------------------------------------------------------+
//| participants > receiver > copy constructor                       |
//+------------------------------------------------------------------+
Receiver::Receiver(Receiver &src)
  {
  }
//+------------------------------------------------------------------+
//| participants > receiver > action                                 |
//+------------------------------------------------------------------+
void Receiver::Action(void)
  {
   Print("receiver ",&this," action");
  }
//+------------------------------------------------------------------+
//| participants > command                                           |
//+------------------------------------------------------------------+
class Command
//   declares operation interface
  {
protected:
   Receiver*         m_receiver;
public:
                     Command(Receiver*);
                    ~Command(void);
   virtual void      Execute(void)=0;
  };
//+------------------------------------------------------------------+
//| participants > command > constructor                             |
//+------------------------------------------------------------------+
Command::Command(Receiver* receiver)
  {
   m_receiver=new Receiver(receiver);
   Print("receiver ",receiver," accepted by command ",&this);
  }
//+------------------------------------------------------------------+
//| participants > command > destructor                              |
//+------------------------------------------------------------------+
Command::~Command(void)
  {
   if(CheckPointer(m_receiver)==1)
     {
      delete m_receiver;
     }
  }
//+------------------------------------------------------------------+
//| participants > concrete command                                  |
//+------------------------------------------------------------------+
class ConcreteCommand:public Command
//   receiver/action binding
//   implements execute() by calling receiver operation
  {
protected:
   int               m_state;
public:
                     ConcreteCommand(Receiver*);
   void              Execute(void);
  };
//+------------------------------------------------------------------+
//| participants > concrete command > constructor                    |
//+------------------------------------------------------------------+
ConcreteCommand::ConcreteCommand(Receiver* receiver):
   Command(receiver),
   m_state(0)
  {
   Print("command ",&this," state: ",m_state);
  }
//+------------------------------------------------------------------+
//| participants > concrete command > execute                        |
//+------------------------------------------------------------------+
void ConcreteCommand::Execute(void)
  {
   Print("command executes receiver ",m_receiver);
   m_receiver.Action();
   m_state=1;
   Print("command ",&this," state: ",m_state);
  }
//+------------------------------------------------------------------+
//| participants > invoker                                           |
//+------------------------------------------------------------------+
class Invoker
//   asks the command to carry out the request
  {
public:
                    ~Invoker(void);
   void              StoreCommand(Command*);
   void              Execute(void);
protected:
   Command*          m_command;
  };
//+------------------------------------------------------------------+
//| participants > invoker > destructor                              |
//+------------------------------------------------------------------+
Invoker::~Invoker(void)
  {
   if(CheckPointer(m_command)==1)
     {
      delete m_command;
     }
  }
//+------------------------------------------------------------------+
//| participants > invoker > command                                 |
//+------------------------------------------------------------------+
void Invoker::StoreCommand(Command* command)
  {
   m_command=command;
   Print("command ",m_command," stored");
  }
//+------------------------------------------------------------------+
//| participants > invoker > execute                                 |
//+------------------------------------------------------------------+
void Invoker::Execute(void)
  {
   Print("executing command ",m_command);
   m_command.Execute();
  }
//+------------------------------------------------------------------+
//| participants > client                                            |
//+------------------------------------------------------------------+
class Client:public ClientExample
//   creates a concrete command object and sets its receiver
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void)
  {
   return __FUNCTION__;
  }
//+------------------------------------------------------------------+
//| collaborations                                                   |
//+------------------------------------------------------------------+
void Client::Run(void)
//   client
//      creates a concrete command
//      specifies its receiver
//   invoker
//      stores the concrete command requests by calling execute()
//      command undoable
//         concrete command stores state prior to execute()
//
//   aReceiver   aClient                    aCommand       anInvoker
//       |          |                          |               |
//       |          |                                          |
//       |         | |newCommand(aReceiver)    |               |
//       |         | |- - - - - - - - - - - ->| |              |
//       |         | |                         |               |
//       |         | |StoreCommand(aCommand)   |               |
//       |         | |-------------------------|------------->| |
//       |          |                          |              | |
//       |          |                          |               |
//       /          /                          /               /
//       /          /                          /               /
//       |          |                          |               |
//       |          |                          |     Execute()| |
//       |          |                 Action()| |<------------| |
//      | |<--------|-------------------------| |             | |
//       |          |                          |               |
  {
   Receiver receiver;
   Invoker invoker;
   invoker.StoreCommand(new ConcreteCommand(&receiver));
   invoker.Execute();
  }
}
//+------------------------------------------------------------------+
//| output                                                           |
//+------------------------------------------------------------------+
//   Command::Client::Output
//   receiver 2097152 accepted by command 4194304
//   command 4194304 state: 0
//   command 4194304 stored
//   executing command 4194304
//   command executes receiver 5242880
//   receiver 5242880 action
//   command 4194304 state: 1
//+------------------------------------------------------------------+
//| consequences                                                     |
//+------------------------------------------------------------------+
//   decouple operation's caller/performer
//   commands are first-class manipulateable/extendable objects
//   assemble commands into a composite command
//   easy to add new commands
//+------------------------------------------------------------------+
//| implementation                                                   |
//+------------------------------------------------------------------+
//   how intelligent is a command
//      binds receiver/actions
//      delegates nothing to receiver
//         commands are independent of the existing classes
//         no receiver exists
//         command knows receiver
//      commands can find receiver dynamically
//   undo and redo
//      concrete command stores additional state
//         receiver
//         operation arguments
//         receiver's original values that can change receiver
//         provides the recover operations
//      multiple-level
//         history list of sequences of commands
//         reverse-execute to cancel
//         maybe copy an undoable command before putting it on list
//   error accumulation in undo
//      delay can be a problem
//      errors can accumulate
//      use memento to store more original state in the command
//       for recover
//   templates for non-undoable/no argument commands
//+------------------------------------------------------------------+
//| related patterns                                                 |
//+------------------------------------------------------------------+
//   composite > implement macrocommands
//   memento > keep state the command requires to undo its effect
//   prototype > a command that must be copied
//    before being placed on the history list
//+------------------------------------------------------------------+
📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks