//+------------------------------------------------------------------+ //|                                                    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 //+------------------------------------------------------------------+