//+------------------------------------------------------------------+
//| ChainOfResponsibility.mqh |
//| 2019-2020, dimitri pecheritsa |
//| 792112@gmail.com |
//+------------------------------------------------------------------+
//| chain of responsibility — behavioral design pattern |
//+------------------------------------------------------------------+
// design patterns: elements of reusable object-oriented software
// gof > erich gamma, richard helm, ralph johnson, john vlissides
// published — 1994
//+------------------------------------------------------------------+
//| intent |
//+------------------------------------------------------------------+
// avoid coupling the sender of a request to its receiver
// by giving more than one object a chance to handle the request
// chain the receiving objects and pass the request along the chain
// until an object handles it
//+------------------------------------------------------------------+
//| benefits |
//+------------------------------------------------------------------+
// aspect that may vary > object that can fulfill a request
// code refactoring
// problems
// dependence on specific operations
// tight coupling
// extending functionality by subclassing
// solutions
// avoid — hard-coded requests
// also > command
// decouple — with abstract coupling and layering
// also > abstract factory, bridge, command, facade,
// mediator, observer
// use composition/delegation — for combining behavior
// also > bridge, composite, decorator, observer, strategy
//+------------------------------------------------------------------+
//| applicability |
//+------------------------------------------------------------------+
// more than one object may handle a request,
// and the handler isn't known a priori
// the handler should be ascertained automatically
// you want to issue a request to one of several objects
// without specifying the receiver explicitly
// the set of objects that can handle a request
// should be specified dynamically
//+------------------------------------------------------------------+
//| structure |
//+------------------------------------------------------------------+
//
// +----------------+
// | |
// v successor |
// |Client|------------>| Handler |-------------+
// |---------------|
// |HandleRequest()|
// ^
// |
// +------------+-------------+
// | |
// |ConcreteHandler1| |ConcreteHandler2|
// |----------------| |----------------|
// |HandleRequest() | |HandleRequest() |
//
//+------------------------------------------------------------------+
//| a typical object structure |
//+------------------------------------------------------------------+
//
// |aClient |
// |-----------| |aConcreteHandler|
// |aHandler *-|----->|----------------| |aConcreteHandler|
// |successor *-|------>|----------------|
// |successor |
//
#include <SRC\Patterns\PatternOrganizer.mqh>
namespace ChainOfResponsibility
{
//+------------------------------------------------------------------+
//| participants > handler |
//+------------------------------------------------------------------+
class Handler
// defines an interface for handling requests
// (optional) implements the successor link
{
public:
Handler* successor;
virtual void HandleRequest(int)=0;
~Handler(void);
};
//+------------------------------------------------------------------+
//| participants > handler > destructor |
//+------------------------------------------------------------------+
Handler::~Handler(void)
{
delete successor;
}
//+------------------------------------------------------------------+
//| participants > concrete handler |
//+------------------------------------------------------------------+
// handles requests it is responsible for
// can access its successor
// if the concretehandler can handle the request, it does so
// else it forwards the request to its successor
//+------------------------------------------------------------------+
//| participants > concrete handler > 1 |
//+------------------------------------------------------------------+
class ConcreteHandler1:public Handler
{
public:
void HandleRequest(int);
};
//+------------------------------------------------------------------+
//| participants > concrete handler > 1 > handle request |
//+------------------------------------------------------------------+
void ConcreteHandler1::HandleRequest(int request)
{
if(request==1)
Print("request: ",request,". response: one. handled by: ",&this);
else
if(CheckPointer(successor))
{
Print("request: ",request,". cannot be handled by ",&this,", forwarding to successor...");
successor.HandleRequest(request);
}
}
//+------------------------------------------------------------------+
//| participants > concrete handler > 2 |
//+------------------------------------------------------------------+
class ConcreteHandler2:public Handler
{
public:
void HandleRequest(int);
};
//+------------------------------------------------------------------+
//| participants > concrete handler > 2 > handle request |
//+------------------------------------------------------------------+
void ConcreteHandler2::HandleRequest(int request)
{
if(request==2)
Print("request: ",request,". response: two. handled by: ",&this);
else
if(CheckPointer(successor))
{
Print("request: ",request,". cannot be handled by ",&this,", forwarding to successor...");
successor.HandleRequest(request);
}
}
//+------------------------------------------------------------------+
//| participants > client |
//+------------------------------------------------------------------+
class Client:public ClientExample
// initiates the request to a concrete handler on the chain
{
public:
string Output();
void Run();
};
string Client::Output()
{
return __FUNCTION__;
}
//+------------------------------------------------------------------+
//| collaborations |
//+------------------------------------------------------------------+
void Client::Run()
// request is sent along the chain until concrete handler handles it
{
Handler* h1=new ConcreteHandler1();
Handler* h2=new ConcreteHandler2();
h1.successor=h2;
h1.HandleRequest(1); // will handle the request
h1.HandleRequest(2); // will pass the request to successor
//---
delete h1;
}
}
//+------------------------------------------------------------------+
//| output |
//+------------------------------------------------------------------+
// ChainOfResponsibility::Client::Output
// request: 1. response: one. handled by: 2097152
// request: 2. cannot be handled by 2097152, forwarding to successor...
// request: 2. response: two. handled by: 3145728
//+------------------------------------------------------------------+
//| consequences |
//+------------------------------------------------------------------+
// reduced coupling
// object does not know who handles a request
// object knows that a request will be handled
// sender does not know receiver
// object does not know the chain structure
// simple object interconnections
// objects do not maintain references to all candidate receivers
// objects keep a reference to successor only
// flexibility in assigning responsibilities to objects
// add/change the chain at run-time
// combine with subclassing to specialize handlers statically
// receipt isn't guaranteed
// request has no explicit receiver
// request can fall off the end of the chain
// also when the chain is not configured properly
//+------------------------------------------------------------------+
//| implementation |
//+------------------------------------------------------------------+
// successor chain
// define new links
// use existing links when the links support the chain
// saves from defining links explicitly
// saves space
// if other structure then define redundant links
// connecting successors
// if no preexisting references for defining a chain
// then handler defines the interface, maintains the successor
// handler provides a default implementation of handlerequest
// concrete handler doesn't have to override the forwarding operation
// representing requests
// request is a hard-coded operation call
// convenient and safe
// can forward only handler's fixed set of requests
// or use a single handler function with request code as a parameter
// supports an open-ended requests
// sender/receiver must agree on encoding
// requires conditional statements for dispatching the request
// less safe than direct call
// can use separate requests that bundle parameters
// request can represent requests explicitly
// can subclass new requests
// subclasses can define different parameters
// handlers must know the kind of request
// identify the request by accessor function — returns class id
// or receiver can use run-time type information
//+------------------------------------------------------------------+
//| related patterns |
//+------------------------------------------------------------------+
// composite > component's parent can act as its successor
//+------------------------------------------------------------------+
#31259LibrariesMetaTrader 5👁 3360 views
Chain of responsibility - behavioral design pattern
D
Author
DMITRII PECHERITSAPublished date
Sep 30, 2020
📚Related Articles
← View other articles →#77531Libraries
CSetupLedger: a per-setup win rate ledger for Expert Advisors
Why I wrote it My scalper trades two setups. A bullish order block and the bearish mirror of it. The Strategy Tester gave me one profit factor for both of them. I spent two weeks t...
Ali AkbarView detail →
#77488Libraries
Position sizing from risk, using the broker's own tick value and volume step
Every lot size calculator that assumes one pip is worth ten dollars is wrong on gold, wrong on indices, wrong on JPY crosses and wrong on any account not denominated in USD which i...
Ralph Ivan SimeonView detail →
#77156Libraries
PropFirm Defense
A prop firm account runs under a second rulebook MetaTrader 5 knows nothing about: a maximum loss measured from a fixed starting balance, a daily limit that resets at an hour the b...
Bruno Nunes Myrrha RibeiroView detail →