Flyweight – structural design pattern – library MetaTrader 5

//+------------------------------------------------------------------+
//|                                                    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
//+------------------------------------------------------------------+
    📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks