Welcome Forex EA downloads & MT4/MT5 auto-trading resources — EAs, Gold EAs, quant tools and real-world automation.
Sign In Sign Up

Commands - Behavioral Design Patterns - MetaTrader 5 Library | MT5 EA Download - MetaTrader 5 Resources

author EAcpu | 3 reads | 0 comments |
//+------------------------------------------------------------------+
//| 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 |
//
#include namespace 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

Verification code Refresh