Composite – structural design pattern – library MetaTrader 5

//+------------------------------------------------------------------+
//|                                                    Composite.mqh |
//|                                    2019-2020, dimitri pecheritsa |
//|                                                 792112@gmail.com |
//+------------------------------------------------------------------+
//| src > patterns > structural > composite                          |
//+------------------------------------------------------------------+
//   design patterns: elements of reusable object-oriented software
//   gof > erich gamma, richard helm, ralph johnson, john vlissides
//   published in 1994
//+------------------------------------------------------------------+
//| intent                                                           |
//+------------------------------------------------------------------+
//   object tree > represents > part-whole hierarchies
//   client > treats uniformly > objects and compositions of objects
//+------------------------------------------------------------------+
//| benefits                                                         |
//+------------------------------------------------------------------+
//   variable aspect > structure and composition of an object
//   refactoring > problem > extending functionality < by subclassing 
//   refactoring > solution > composition/delegation > combine behavior
//      also > bridge, chain of responsibility, composite, decorator,
//       observer, strategy
//+------------------------------------------------------------------+
//| applicability                                                    |
//+------------------------------------------------------------------+
//   represent > part-whole hierarchies of objects
//   clients > ignore > difference
//      compositions of objects and individual objects
//   clients > treat uniformly > composite structure objects
//+------------------------------------------------------------------+
//| structure                                                        |
//+------------------------------------------------------------------+
//
//     |Client|----->|    Component    |*<------------------+
//                   |-----------------|                    |
//                   |Operation()      |                    | 
//                   |Add(Component)   |                    |
//                   |Remove(Component)|                    |
//                   |GetChild(int)    |                    |
//                            ^                             |
//                            |                             |
//                    +-------+-----------+                 |
//                    |                   |           nodes |
//              |   Leaf    |   |     Composite     |o------+
//              |-----------|   |-------------------|
//              |Operation()|   |Operation()        |
//                              | for all n in nodes|
//                              |  n.Operation()    |
//                              |Add(Component)     |
//                              |Remove(Component)  |
//                              |GetChild(int)      |
//
//+------------------------------------------------------------------+
//| typical object structure                                         |
//+------------------------------------------------------------------+
//
//                        +---->|aLeaf|
//                        |
//       |aComposite|-----+---->|aLeaf|         +---->|aLeaf|
//                        |                     |
//                        +---->|aComposite|----+---->|aLeaf|
//                        |                     |
//                        +---->|aLeaf|         +---->|aLeaf|
//
#include <SRCPatternsPatternOrganizer.mqh>
namespace Composite
{
//+------------------------------------------------------------------+
//| participants                                                     |
//+------------------------------------------------------------------+
class Component
//   declares > interface 
//      objects < composition
//      accessing and managing child components
//   default behavior > interface > common to all classes
//   optional > interface
//      accessing > component's parent in the recursive structure
//      implements it if that's appropriate
  {
public:
   virtual void      Operation(void)=0;
   virtual void      Add(Component*)=0;
   virtual void      Remove(Component*)=0;
   virtual Component*   GetChild(int)=0;
                     Component(void);
                     Component(string);
protected:
   string            name;
  };
Component::Component(void) {}
Component::Component(string a_name):name(a_name) {}
//+------------------------------------------------------------------+
//| participants                                                     |
//+------------------------------------------------------------------+
#define ERR_INVALID_OPERATION_EXCEPTION   1
//user error for adding/removing a component to a leaf
class Leaf:public Component
//   represents > leaf objects < composition
//   no children
//   defines > behavior > primitive objects in the composition
  {
public:
   void              Operation(void);
   void              Add(Component*);
   void              Remove(Component*);
   Component*        GetChild(int);
                     Leaf(string);
  };
void Leaf::Leaf(string a_name):Component(a_name) {}
void Leaf::Operation(void) {Print(name);}
void Leaf::Add(Component*) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION);}
void Leaf::Remove(Component*) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION);}
Component* Leaf::GetChild(int) {SetUserError(ERR_INVALID_OPERATION_EXCEPTION); return NULL;}
//+------------------------------------------------------------------+
//| participants                                                     |
//+------------------------------------------------------------------+
class Composite:public Component
//   defines > behavior for components having children
//   stores > child components
//   implements > child-related operations > in component interface
  {
public:
   void              Operation(void);
   void              Add(Component*);
   void              Remove(Component*);
   Component*        GetChild(int);
                     Composite(string);
                    ~Composite(void);
protected:
   Component*        nodes[];
  };
Composite::Composite(string a_name):Component(a_name) {}
//+------------------------------------------------------------------+
//| participants > composite                                         |
//+------------------------------------------------------------------+
Composite::~Composite(void)
  {
   int total=ArraySize(nodes);
   for(int i=0; i<total; i++)
     {
      Component* i_node=nodes[i];
      if(CheckPointer(i_node)==1)
        {
         delete i_node;
        }
     }
  }
//+------------------------------------------------------------------+
//| participants > composite                                         |
//+------------------------------------------------------------------+
void Composite::Operation(void)
  {
   Print(name);
   int total=ArraySize(nodes);
   for(int i=0; i<total; i++)
     {
      nodes[i].Operation();
     }
  }
//+------------------------------------------------------------------+
//| participants > composite                                         |
//+------------------------------------------------------------------+
void Composite::Add(Component *src)
  {
   int size=ArraySize(nodes);
   ArrayResize(nodes,size+1);
   nodes[size]=src;
  }
//+------------------------------------------------------------------+
//| participants > composite                                         |
//+------------------------------------------------------------------+
void Composite::Remove(Component *src)
  {
   int find=-1;
   int total=ArraySize(nodes);
   for(int i=0; i<total; i++)
     {
      if(nodes[i]==src)
        {
         find=i;
         break;
        }
     }
   if(find>-1)
     {
      ArrayRemove(nodes,find,1);
     }
  }
//+------------------------------------------------------------------+
//| participants > composite                                         |
//+------------------------------------------------------------------+
Component* Composite::GetChild(int i)
  {
   return nodes[i];
  }
//+------------------------------------------------------------------+
//| participants                                                     |
//+------------------------------------------------------------------+
class Client:public ClientExample
//   manipulates objects in the composition through the component interface
  {
public:
   string            Output(void);
   void              Run(void);
  };
string Client::Output(void) {return __FUNCTION__;}
//+------------------------------------------------------------------+
//| collaborations                                                   |
//+------------------------------------------------------------------+
void Client::Run(void)
//   clients use the component class interface
//      to interact with objects in the composite structure
//   if the recipient is a leaf > the request is handled directly
//   if the recipient is a composite
//      it usually forwards requests to its child components
//      possibly performing additional operations
//       before and/or after forwarding
  {
   Component* root=new Composite("root"); //make root
//---make components
   Component* branch1=new Composite(" branch 1");
   Component* branch2=new Composite(" branch 2");
   Component* leaf1=new Leaf("  leaf 1");
   Component* leaf2=new Leaf("  leaf 2");
//---build tree
   root.Add(branch1);
   root.Add(branch2);
   branch1.Add(leaf1);
   branch1.Add(leaf2);
   branch2.Add(leaf2);
   branch2.Add(new Leaf("  leaf 3"));
//---check
   printf("tree:");
   root.Operation();
//---change tree
   root.Remove(branch1); //remove whole branch
//---check
   printf("tree after removal of one branch:");
   root.Operation();
//---finish
   delete root;
   delete branch1;
  }
}
//+------------------------------------------------------------------+
//| output                                                           |
//+------------------------------------------------------------------+
//   Structural::Composite::Client::Output
//   tree:
//   root
//    branch 1
//     leaf 1
//     leaf 2
//    branch 2
//     leaf 2
//     leaf 3
//   tree after removal of one branch:
//   root
//    branch 2
//     leaf 2
//     leaf 3
//+------------------------------------------------------------------+
//| consequences                                                     |
//+------------------------------------------------------------------+
//   defines class hierarchies consisting of primitive objects and composite objects
//   makes the client simple
//   makes it easier to add new kinds of components
//   can make your design overly general
//+------------------------------------------------------------------+
//| implementation                                                   |
//+------------------------------------------------------------------+
//   explicit parent references (in component)
//      simplify the traversal and management of a composite structure
//      help support the chain of responsibility pattern
//   sharing components
//      flyweight can rework a design to avoid storing parents altogether
//   maximizing the component interface
//      default implementations, leaf and composite will override them
//   declaring the child management operations
//      at the root of the class hierarchy > transparency
//      in the composite > afety
//      usually it's better to make add and remove fail by default
//         if the component isn't allowed to have children
//         or if the argument of remove isn't a child of the component
//   component may implement a list of components
//      if there are relatively few children in the structure
//   child ordering > design child access/management carefully > iterator
//   caching to improve performance
//      when components know their parents
//      tell composites that their caches are invalid
//   composite is responsible for deleting its children
//      when it's destroyed, unless leafs can be shared
//   composites store children in
//      linked lists, trees, arrays, and hash tables
//+------------------------------------------------------------------+
//| related patterns                                                 |
//+------------------------------------------------------------------+
//   chain of responsibility > component-parent link
//   decorator > common parent class > for decorators and composites
//   flyweight > share components (no longer refer to their parents)
//   iterator > traverse composites
//   visitor > localizes operations and behavior
//      distributed across composite and leaf classes
//+------------------------------------------------------------------+
    📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks