//+------------------------------------------------------------------+
//| Visitor.mq5 |
//| 2019-2020, dimitri pecheritsa |
//| 792112@gmail.com |
//+------------------------------------------------------------------+
//
// visitor - behavioral design pattern
//
// from: design patterns: elements of reusable object-oriented software
// by gof: erich gamma, richard helm, ralph johnson, john vlissides
// published in 1994
//
// intent
//
// represent an operation to be performed on the elements of an object
//structure. visitor lets you define a new operation without changing
//the classes of the elements on which it operates.
//
// applicability
//
// use the visitor pattern when
// an object structure contains many classes of objects with differing
//interfaces, and you want to perform operations on these objects that
//depend on their concrete classes.
// many distinct and unrelated operations need to be performed on
//objects in an object structure, and you want to avoid "polluting" their
//classes with these operations. visitor lets you keep related operations
//together by defining them in one class. when the object structure is
//shared by many applications, use visitor to put operations in just those
//applications that need them.
// the classes defining the object structure rarely change, but you
//often want to define new operations over the structure. changing the
//object structure classes requires redefining the interface to all visitors,
//which is potentially costly. if the object structure classes change
//often, then it's probably better to define the operations in those classes.
//
// structure
//
//|Client|---------->| Visitor |
// | |---------------------------------------|
// | |VisitConcreteElementA(ConcreteElementA)|
// | |VisitConcreteElementB(ConcreteElementB)|
// | ^
// | |
// | +---------------+---------------+
// | | |
// | | ConcreteVisitor1 | | ConcreteVisitor2 |
// | |---------------------- | |-----------------------|
// | |VisitConcreteElementA( | |VisitConcreteElementA( |
// | | ConcreteElementA) | | ConcreteElementA) |
// | |VisitConcreteElementB( | |VisitConcreteElementB( |
// | | ConcreteElementB) | | ConcreteElementB) |
// |
// |
// +--->|ObjectStructure|--->*| Element |
// |---------------|
// |Accept(Visitor)|
// ^
// |
// +------------------+------------------+
// | |
// | ConcreteElementA | | ConcreteElementB |
// |------------------------------| |------------------------------|
// |Accept(Visitor) | |Accept(Visitor) |
// | v.VisitConcreteElementA(this)| | v.VisitConcreteElementB(this)|
// |OperationA() | |OperationB() |
//
//
// participants
//
// visitor
// declares a visit operation for each class of concrete element
//in the object structure. the operation's name and signature identifies
//the class that sends the visit request to the visitor. that lets the
//visitor determine the concrete class of the element being visited. then
//the visitor can access the element directly through its particular interface.
// concrete visitor
// implements each operation declared by visitor. each operation
//implements a fragment of the algorithm defined for the corresponding
//class of object in the structure. concrete visitor provides the context
//for the algorithm and stores its local state. this state often accumulates
//results during the traversal of the structure.
// element
// defines an accept operation that takes a visitor as an argument.
// concrete element
// implements an accept operation that takes a visitor as an argument.
// object structure
// can enumerate its elements.
// may provide a high-level interface to allow the visitor to visit
//its elements.
// may either be a composite or a collection such as a list or a set.
//
// collaborations
//
// a client that uses the visitor pattern must create a concrete visitor
//object and then traverse the object structure, visiting each element
//with the visitor.
// when an element is visited, it calls the visitor operation that corresponds
//to its class. the element supplies itself as an argument to this operation
//to let the visitor access its state, if necessary.
// the following interaction diagram illustrates the collaborations
//between an object structure, a visitor, and two elements:
//
// anObject aConcreteElementA aConcreteElementB aConcreteVisitor
// Structure | | |
// | | | |
// | |Accept(aVisitor) | | |
// | |---------------->| |VisitConcreteElementA(aConcreteElementA) |
// | | | |------------------|-------------------->| |
// | | | | | |
// | | | |<-----------------|---------------------| |
// | |Accept(aVisitor) | | |
// | |------------------|----------------->| |VisitConcrete |
// | | | | | ElementB(aConcrete | |
// | | | | | ElementB) | |
// | | | | |------------------->| |
// | | | | | |
// | | | | |<-------------------| |
// | | | |
//
//+------------------------------------------------------------------+
//| example of a client |
//+------------------------------------------------------------------+
#include <Mqh\Patterns\Visitor\ObjectStructure.mqh>
#include <Mqh\Patterns\Visitor\Element.mqh>
#include <Mqh\Patterns\Visitor\ConcreteElementA.mqh>
#include <Mqh\Patterns\Visitor\ConcreteElementB.mqh>
#include <Mqh\Patterns\Visitor\Visitor.mqh>
#include <Mqh\Patterns\Visitor\ConcreteVisitor1.mqh>
#include <Mqh\Patterns\Visitor\ConcreteVisitor2.mqh>
void OnStart()
{
ObjectStructure structure;
structure.Add(new ConcreteElementA());
structure.Add(new ConcreteElementB());
structure.Accept(new ConcreteVisitor1());
structure.Accept(new ConcreteVisitor2());
}
// output
//
// element 2097152 added to the object structure
// element 3145728 added to the object structure
//
// object structure has accepted new visitor 4194304
// object structure has 2 elements
// object structure is requesting each element to accept the visitor
// element a has accepted the visitor
// the element made operation a
// element b has accepted the visitor
// the element made operation b
//
// object structure has accepted new visitor 5242880
// object structure has 2 elements
// object structure is requesting each element to accept the visitor
// element a has accepted the visitor
// the element made operation a
// element b has accepted the visitor
// the element made operation b
//
//
// consequences
//
// some of the benefits and liabilities of the visitor pattern are as
//follows:
// visitor makes adding new operations easy
// a visitor gathers related operations and separates unrelated ones
// adding new concrete element classes is hard
// visiting across class hierarchies
// accumulating state
// breaking encapsulation
//
// implementation
//
// each object structure will have an associated visitor class. this
//abstract visitor class declares a visit concrete element operation for
//each class of concrete element defining the object structure. each visit
//operation on the visitor declares its argument to be a particular concrete
//element, allowing the visitor to access the interface of the concrete
//element directly. concrete visitor classes override each visit operation
//to implement visitor-specific behavior for the corresponding concrete
//element class.
// here are two other implementation issues that arise when you apply
//the visitor pattern:
// double dispatch
// who is responsible for traversing the object structure?
//
// related patterns
//
// composite: visitors can be used to apply an operation over an object
//structure defined by the composite pattern.
// interpreter: visitor may be applied to do the interpretation.
Comments