//+------------------------------------------------------------------+ //|                                                    Flyweight.mqh | //|                                    2019-2020, dimitri pecheritsa | //|                                                792112@gmail.com | //+------------------------------------------------------------------+ //| flyweight > structural design pattern                            | //+------------------------------------------------------------------+ //  design patterns: elements of reusable object-oriented software //  gof > erich gamma, richard helm, ralph johnson, john vlissides //  published > 1994 //+------------------------------------------------------------------+ //| intent                                                          | //+------------------------------------------------------------------+ //  use sharing to support large numbers of fine-grained objects //    efficiently //+------------------------------------------------------------------+ //| applicability                                                    | //+------------------------------------------------------------------+ //  an application uses a large number of objects //  storage costs are high because of the sheer quantity of objects //  most object state can be made extrinsic //  many groups of objects may be replaced by relatively few //    shared objects once extrinsic state is removed //  the application doesn't depend on object identity //      since flyweight objects may be shared, identity tests will //      return true for conceptually distinct objects //+------------------------------------------------------------------+ //| structure                                                        | //+------------------------------------------------------------------+ // //      |      FlyweightFactory    |o------------------>*|        Flyweight        | //      |---------------------------|                    |--------------------------| //  +->|GetFlyweight(key)          |                    |Operation(extrinsic_state)| //  |  | if(flyweight[key] exists) |                                  ^ //  |  |  return existing flyweight|                                  | //  |  | else                      |                  +---------------+----------------+ //  |  |  create new flyweight    |                  |                                | //  |  |  add it to the pool of    |  +->|    ConcreteFlyweight    |  +->|UnsharedConcreteFlyweight | //  |  |  flyweights              |  |  |--------------------------|  |  |--------------------------| //  |  |  return the new flyweight |  |  |Operation(extrinsic_state)|  |  |Operation(extrinsic_state)| //  |                                  |  |--------------------------|  |  |--------------------------| //  |                                  |  |intrinsic_state          |  |  |all_state                | //  |                                  |                                | //|Client|------------------------------+---------------------------------+ // //+------------------------------------------------------------------+ //| diagram — sharing of flyweights                                  | //+------------------------------------------------------------------+ // //                                      |aClient|              |aClient| //                                      |-------|              |-------| //                                      |  *  |  +-----------|-* *  | //                                          |      |              | //                            +------------|------|---------------|--------------+ //                            |flyweights  |      |              |              | //                            |pool        |      |              |              | //                            |            v      v              v              | //|aFlyweightFactory|          |  |ConcreteFlyweight|      |ConcreteFlyweight|  | //|-----------------|          |  |-----------------|      |-----------------|  | //|flyweights  *---|----+-----|-->|intrinsic_state  |  +->|intrinsic_state  |  | //                      |    |                        |                        | //                      +-----|-------------------------+                        | //                            +--------------------------------------------------+ // #include <SRCPatternsPatternOrganizer.mqh> namespace Flyweight { //+------------------------------------------------------------------+ //| include — flyweight dictionary — service class                  | //+------------------------------------------------------------------+ #include "ServiceFlyweightDictionary.mqh" //+------------------------------------------------------------------+ //| participants > flyweight — interface                            | //+------------------------------------------------------------------+ interface Flyweight //  declares an interface through which flyweights can receive //    and act on extrinsic state   {   void Operation(int extrinsic_state);   }; //+------------------------------------------------------------------+ //| participants > concrete flyweight                                | //+------------------------------------------------------------------+ class ConcreteFlyweight:public Flyweight //  implements the flyweight interface and adds storage for //    intrinsic state, if any //  a concrete flyweight object must be sharable //  any state it stores must be intrinsic //      that is, it must be independent of the concrete flyweight //      object's context   { public:   void              Operation(int extrinsic_state); protected:   int              intrinsic_state;   }; //+------------------------------------------------------------------+ //| participants > concrete flyweight > operation                    | //+------------------------------------------------------------------+ void ConcreteFlyweight::Operation(int extrinsic_state)   {   intrinsic_state=extrinsic_state;   printf("intrinsic state: %d",intrinsic_state);   } //+------------------------------------------------------------------+ //| participants > unshared concrete flyweight                      | //+------------------------------------------------------------------+ class UnsharedConcreteFlyweight:public Flyweight //  not all flyweight subclasses need to be shared //  the flyweight interface enables concrete sharing — it doesn't enforce it //  it's common for unshared concrete flyweight objects to have //    concrete flyweight objects as children at some level //    in the flyweight object structure   { protected:   int              all_state; public:   void              Operation(int extrinsic_state);   }; //+------------------------------------------------------------------+ //| participants > unshared concrete flyweight > operation          | //+------------------------------------------------------------------+ void UnsharedConcreteFlyweight::Operation(int extrinsic_state)   {   all_state=extrinsic_state;   printf("all state: %d",all_state);   } //+------------------------------------------------------------------+ //| participants > flyweight factory                                | //+------------------------------------------------------------------+ class FlyweightFactory //  creates and manages flyweight objects //  ensures that flyweights are shared properly //      when a client requests a flyweight, the flyweight factory //      object supplies an existing instance or creates one, //      if none exists   { protected:   Dictionary        pool; public:                     FlyweightFactory(void);   Flyweight*        Flyweight(string key);   }; //+------------------------------------------------------------------+ //| participants > flyweight factory > constructor                  | //+------------------------------------------------------------------+ FlyweightFactory::FlyweightFactory(void)   {   pool.Add("1",new ConcreteFlyweight);   pool.Add("2",new ConcreteFlyweight);   pool.Add("3",new ConcreteFlyweight);   } //+------------------------------------------------------------------+ //| participants > flyweight factory > get flyweight                | //+------------------------------------------------------------------+ Flyweight* FlyweightFactory::Flyweight(string key)   {   if(!pool.Has(key)) //pool has no such key     {       pool.Add(key,new ConcreteFlyweight()); //create new key—flyweight pair     }   return pool[key]; //return flyweight at key   } //+------------------------------------------------------------------+ //| participants > client                                            | //+------------------------------------------------------------------+ class Client:public ClientExample //  maintains a reference to flyweight(s) //  computes or stores the extrinsic state of flyweight(s)   { public:   string            Output();   void              Run();   }; string Client::Output(void)   {   return __FUNCTION__;   } //+------------------------------------------------------------------+ //| collaborations                                                  | //+------------------------------------------------------------------+ void Client::Run(void) //  state that a flyweight needs to function must be characterized //    as either intrinsic or extrinsic //      intrinsic state is stored in the concrete flyweight object //      extrinsic state is stored or computed by client objects //      clients pass this state to the flyweight when they invoke //      its operations //  clients should not instantiate concrete flyweights directly //      clients must obtain concrete flyweight objects exclusively //      from the flyweight factory object to ensure they are shared //      properly   {   int extrinsic_state=7;   Flyweight* flyweight;   FlyweightFactory factory; //---the extrinsic state is relayed to all flyweights   flyweight=factory.Flyweight("1");   flyweight.Operation(extrinsic_state);   flyweight=factory.Flyweight("10");   flyweight.Operation(extrinsic_state); //---   flyweight=new UnsharedConcreteFlyweight();   flyweight.Operation(extrinsic_state);   delete flyweight;   } } //+------------------------------------------------------------------+ //| output                                                          | //+------------------------------------------------------------------+ //  Flyweight::Client::Output //  intrinsic state: 7 //  intrinsic state: 7 //  all state: 7 //+------------------------------------------------------------------+ //| consequences                                                    | //+------------------------------------------------------------------+ //  flyweights may introduce run-time costs associated with //    transferring, finding, and/or computing extrinsic state, //    especially if it was formerly stored as intrinsic state //  however, such costs are offset by space savings, //    which increase as more flyweights are shared //  storage savings //      are a function of several factors //        the reduction in the total number of instances //          that comes from sharing //        the amount of intrinsic state per object //        whether extrinsic state is computed or stored //      the more flyweights are shared, the greater the storage savings //      the savings increase with the amount of shared state //      the greatest savings occur when the objects use substantial //      quantities of both intrinsic and extrinsic state, //      and the extrinsic state can be computed rather than stored //      then you save on storage in two ways //        sharing reduces the cost of intrinsic state, //        and you trade extrinsic state for computation time //  the flyweight pattern is often combined with the composite pattern //    to represent a hierarchical structure as a graph with shared leaf nodes //      a consequence of sharing is that flyweight leaf nodes //      cannot store a pointer to their parent //      rather, the parent pointer is passed to the flyweight //      as part of its extrinsic state //      this has a major impact on how the objects in the hierarchy //      communicate with each other //+------------------------------------------------------------------+ //| implementation                                                  | //+------------------------------------------------------------------+ //  removing extrinsic state //      can be computed from a separate object structure, //      one with far smaller storage requirements //  managing shared objects //      clients shouldn't instantiate them directly //      clients locate a particular flyweight from associative store //      also implies some form of reference counting or garbage collection //+------------------------------------------------------------------+ //| related patterns                                                | //+------------------------------------------------------------------+ //  composite //      hierarchical structure in terms of a //      directed-acyclic graph with shared leaf nodes //  state, strategy > as flyweights //+------------------------------------------------------------------+