Commands - Behavioral Design Patterns - MetaTrader 5 Library | MT5 EA Download - MetaTrader 5 Resources
//+------------------------------------------------------------------+ //| command.mqh | //| 2019-2020, Dimitri Pecherica| //| 792112@gmail.com | //+------------------------------------------------------------------+ //|Command - Behavioral Design Pattern | //+------------------------------------------------------------------+ // Design patterns: elements of reusable object-oriented software // gof > Erich Gamma, Richard Helm, Ralph Johnson, John Freesides // Published — 1994 //+------------------------------------------------------------------+ //|Intent | //+------------------------------------------------------------------+ // Encapsulate the request as an object // This allows you to parameterize clients with different requests // Queue or record requests and support undoable operations //+------------------------------------------------------------------+ //|Benefits| //+------------------------------------------------------------------+ // Variable side > when and how to fulfill the request // Refactor // question // Depends on specific operations // tight coupling // solution // Avoid hardcoding requests > additionally > chain of responsibility // Decoupling through abstract coupling and layering // also> abstract factory, bridge, responsibility chain, // appearance, mediator, observer //+------------------------------------------------------------------+ //|Applicability | //+------------------------------------------------------------------+ // Parameterize the object with the operation to be performed // Specify, queue and execute requests at different times // Command independent of original request //Support undo //Support change log //Reapply after system crash // Add load/store to command // Reload from disk //Re-execute with execute // Build the system around high-level operations //Build based on primitive operations //+------------------------------------------------------------------+ //|Structure | //+------------------------------------------------------------------+ // // |client| |prayer|o------------------------>|command| // | | |---------| // | |Execute()| // | +-------->|Receiver| ^ // |--------| receiver | // | |Action()|<--------------| Specific command| // |--------------------------------| // | |Execute() | // |Receiver.Action()| // | |------------------| // + - - - - - - - - - - - - - - - - - - - >|Status | // #includenamespace command { //+----------------------------------------------------------------------------------+ //|Participant>Receiver| //+------------------------------------------------------------------+ class Receiver // Knows how to perform the requested operation // Any class can be a Receiver { public : Receiver( blank ); Receiver(receiver&); void Action( Blank ); }; //+------------------------------------------------------------------+ // | Actor > Receiver > Default | //+--------------------------------------------------------------------------------+ Receiver::Receiver( Blank ) { } //+----------------------------------------------------------------+ // | Actor > Receiver > Copy Constructor | //+------------------------------------------------------------------+ Receiver::Receiver(receiver&src) { } //+------------------------------------------------------------------+ //| Actor > Receiver > Action | //+------------------------------------------------------------------+ Blank Receiver::Action ( blank ) { print ( "Receiver" , & this , " Action " ); } //+------------------------------------------------------------------+ // | Participant > Command //+----------------------------------------------------------------+ Class command //+ declare operation interface { protected : receiver * m_receiver; public : command(receiver*); ~command( blank ); virtual void execute( blank ) = 0 ; }; //+------------------------------------------------------------------+ //| Actor > Command > Constructor | //+------------------------------------------------------------------+ Command::command(receiver*receiver) { m_receiver = new Receiver(receiver); print ( "receiver" , "Command accepted" ,& this ); } //+--------------------------------------------------------------------------------+ //|Participant > Command > Destructor | //+------------------------------------------------------------------+ Command::~command( blank ) { if ( check pointer (m_receiver) == 1 ) { Delete m_receiver; } } //+--------------------------------------------------------------------------------+ //|Participant > Specific command | //+------------------------------------------------------------------+ Class specific command: public command //+ Receiver/Action Binding // Implemented by calling the receiver action execute() { protected : integer m_state; public : concrete command(receiver*); blank execute( blank ); }; //+------------------------------------------------------------------+ //|actor>concrete command>constructor | //+------------------------------------------------------------------+ ConcreteCommand::ConcreteCommand(receiver*receiver): command(receiver), m_state( 0 ) { print ( "order" ,& this , "State: " ,m_state); } //+--------------------------------------------------------------------------------+ //| Actor > Specific command > Execution | //+------------------------------------------------------------------+ Blank Specific command::Execute( blank ) { print ( "command execution receiver" ,m_receiver); m_receiver.Action(); m_state = 1 ; print ( "command" ,& this , "state:" ,m_state); } //+------------------------------------------------------------------+ //|Actor > Caller | //+------------------------------------------------------------------+ Class Prayer // Request command execution request { public : ~Prayer( blank ); Blank stored command(Command*); Blank execute( Blank ); Protected : command* m_command; }; { if ( check pointer (m_command) == 1 ) { delete m_command; } } // +------------------------------------------------------------------+ // |actor>caller>command | // +------------------------------------------------------------------ + blank caller::StoreCommand(command*command) { m_command=command; print ( "command" , m_command, "stored" ); } //+------------------------------------------------------------------+ //|actor>caller>execute | //+------------------------------------------------------------------+ Blank caller::execute( blank ) { print ( "Execute command" , m_command); m_command.Execute(); } //+------------------------------------------------------------------+ //|Participant > Client | //+------------------------------------------------------------------+ Class Client: People Client Example // Create a specific command object and set its receiver { People : string output( blank ); } ; string client ::output( blank ) { return __function__ ; } //+------------------------------------------------------------------+ //|Cooperation | //+------------------------------------------------------------------+ blank client :: run( blank ) // Client // Create a specific command // Specify its receiver // Caller // Store the specific command request by calling execute() // The command can be undone // The specific command stores state before execute() // aReceiver aClient aCommand anInvoker // | | | |span class="comment">// | | | // | | |newCommand(aReceiver) | | // | | |- - - - - - - - - - >| | | // | | | | | // | | |StoreCommand(aCommand) | | // | | |--------------------------|-------------> | | // | | | action ()| |<---------------------| | // | Receiver 2097152 Accepted by command 4194304 // Command 4194304 Status: 0 // Command 4194304 stored // Execution of command 4194304 // Command execution Receiver 5242880 // Receiver 5242880 operation // Command 4194304 Status: 1 // + --------------------------------------------------------------------------------+ // | Consequences | //+------------------------------------------------------------------+ // Decouple callers/executors of operations // Commands are first - class operable /extensible objects // Assemble commands into compound commands // Easily add new commands // +------------------------------------------------------------------+ //|Implementation | //+------------------------------------------------------------------+ // How smart is the command // Bind receivers /actions // Don't delegate anything to the receiver // Commands are independent of existing classes // No receiver is known to the command // There is no receiver // Commands can dynamically look up receivers // Undo and redo // Specific commands store additional state // Receivers // Operation parameters // The original value of the receiver can change the receiver // Provide recovery operations // Multi-level // History list of command sequences // Reverse execution to cancel // An irreversible command can be copied before putting it in the list // Error accumulation in undo // Latency can be a problem // Errors accumulate // Use memento Store more original state in the command // Template for restoring // irrevocable/no-argument commands //+------------------------------------------------------------------+ //|Related modes | //+------------------------------------------------------------------+ // Compound > Implement macro command // Memo > Keep aliveThe state of a command whose effect needs to be undone // Prototype > Command that must be copied // before being placed in the history list //+------------------------------------------------------------------+
Attachment download
📎 pattern.mq5 (2.2 KB)
📎 patternorganizer.mqh (16.66 KB)
📎 command.mqh (25.79 KB)
Source: MQL5 #31361
💡 Featured Recommendations
✍️ Latest by the author
- •
- •
- •
- •
- •
- •
📌 Popular topics
- •
- •
- •
- •
- •
- •
- •
- •
🔗 You May Be Interested In
- •
- •
- •
- •
- •
- •