//+------------------------------------------------------------------+
//| 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 <SRC\Patterns\PatternOrganizer.mqh>
namespace Flyweight
{
//+------------------------------------------------------------------+
//| include — flyweight dictionary — service class |
//+------------------------------------------------------------------+
#include "Service\FlyweightDictionary.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
//+------------------------------------------------------------------+
#31061LibrariesMetaTrader 5👁 3725 views
Flyweight - structural design pattern
D
Author
DMITRII PECHERITSAPublished date
Sep 16, 2020
📚Related Articles
← View other articles →#77531Libraries
CSetupLedger: a per-setup win rate ledger for Expert Advisors
Why I wrote it My scalper trades two setups. A bullish order block and the bearish mirror of it. The Strategy Tester gave me one profit factor for both of them. I spent two weeks t...
Ali AkbarView detail →
#77488Libraries
Position sizing from risk, using the broker's own tick value and volume step
Every lot size calculator that assumes one pip is worth ten dollars is wrong on gold, wrong on indices, wrong on JPY crosses and wrong on any account not denominated in USD which i...
Ralph Ivan SimeonView detail →
#77156Libraries
PropFirm Defense
A prop firm account runs under a second rulebook MetaTrader 5 knows nothing about: a maximum loss measured from a fixed starting balance, a daily limit that resets at an hour the b...
Bruno Nunes Myrrha RibeiroView detail →