//+----------------+----------------------------------------------------------------------------------------+
//| Abstract | Provide an interface for creating families of related or dependent objects without |
//| Factory | specifying their concrete classes. |
//+----------------+----------------------------------------------------------------------------------------+
//| When | 1) a system should be independent of how its products are created, composed, and |
//| | represented. 2) a system should be configured with one of multiple families of |
//| | products. 3) a family of related product objects is designed to be used together, and |
//| | you need to enforce this constraint. 4) you want to provide a class library of |
//| | products, and you want to reveal just their interfaces, not their implementations. |
//+----------------+----------------------------------------------------------------------------------------+
//| Structure |
//+---------------------------------------------------------------------------------------------------------+
//
// +----------------+ +------+
// | AbstractFactory|<-------------------------------------------------------------|Client|
// +----------------+ +------+
// |CreateProductA()| +----------------+ |
// |CreateProductA()| |AbstractProductA|<---------------+
// +----------------+ +----------------+ |
// ^ ^ |
// | | |
// +-----------+-----------+ +-------+------+ |
// | | | | |
// +----------------+ +----------------+ +---------+ +---------+ |
// |ConcreteFactory1|- + |ConcreteFactory2|- - - - + - - >|ProductA2| |ProductA1|<- - - + |
// +----------------+ | +----------------+ | +---------+ +---------+ | |
// |CreateProductA()| |CreateProductA()| |
// |CreateProductB()| | |CreateProductB()| | | |
// +----------------+ +----------------+ |
// | | | |
// +----------------+ |
// | | |AbstractProductB|<---------|-----+
// +----------------+
// | | ^ |
// |
// | | +-------+------+ |
// | |
// | | +---------+ +---------+ |
// + - - >|ProductB2| |ProductB1|<- - - +
// | +---------+ +---------+ |
//
// | |
// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
//
//+-----+----------+----------------------------------------------------------------------------------------+
//| Who | Abstract | declares an interface for operations that create abstract product objects. |
//| | Factory | |
//| +----------+----------------------------------------------------------------------------------------+
//| | Concrete | implements the operations to create concrete product objects. |
//| | Factory | |
//| +----------+----------------------------------------------------------------------------------------+
//| | Abstract | declares an interface for a type of product object. |
//| | Product | |
//| +----------+----------------------------------------------------------------------------------------+
//| | Concrete | 1) defines a product object to be created by the corresponding concrete factory. 2) |
//| | Product | implements the AbstractProduct interface. |
//| +----------+----------------------------------------------------------------------------------------+
//| | Client | uses only interfaces declared by AbstractFactory and AbstractProduct classes. |
//+-----+----------+----------------------------------------------------------------------------------------+
//| How | 1) Normally a single instance of a ConcreteFactory class is created at run-time. This |
//| | concrete factory creates product objects having a particular implementation. To |
//| | create different product objects, clients should use a different concrete factory. 2) |
//| | AbstractFactory defers creation of product objects to its ConcreteFactory subclass. |
//+----------------+----------------------------------------------------------------------------------------+
//| Why | 1) It isolates concrete classes: Clients manipulate instances through their abstract |
//| | interfaces. 2) It makes exchanging product families easy: use different product |
//| | configurations simply by changing the concrete factory; the whole product family |
//| | changes at once. 3) It promotes consistency among products. 4) Supporting new kinds |
//| | of products is difficult: requires extending the factory interface, AbstractFactory |
//| | class and all of its subclasses. |
//+----------------+----------------------------------------------------------------------------------------+
//| Notes | 1) Factories as singletons. 2) Creating the products: define a factory method for |
//| | each product. If many product families are possible, the concrete factory can be a |
//| | Prototype: no new concrete factory class for each new product family. 3) Defining |
//| | extensible factories: AbstractFactory will only need a single "Make" operation with a |
//| | parameter indicating the kind of object to create; all objects have the same abstract |
//| | base class. |
//+----------------+----------------------------------------------------------------------------------------+
//| Code |
//+---------------------------------------------------------------------------------------------------------+
#include <SRC\Patterns\Patterns.mqh>
namespace AbstractFactory
{
interface AbstractProductA {};
interface AbstractProductB {void Interact(AbstractProductA*);};
interface AbstractFactory
{
AbstractProductA* CreateProductA();
AbstractProductB* CreateProductB();
};
//--------------------------------------------------------------------
class ProductA1:public AbstractProductA {public:ProductA1(); ~ProductA1();};
void ProductA1::ProductA1(void) {Print(" Product A1 constructed.");}
void ProductA1::~ProductA1(void) {Print(" Product A1 destructed.");}
//--------------------------------------------------------------------
class ProductA2:public AbstractProductA {public:ProductA2(); ~ProductA2();};
void ProductA2::ProductA2(void) {Print(" Product A2 constructed.");}
void ProductA2::~ProductA2(void) {Print(" Product A2 destructed.");}
//--------------------------------------------------------------------
class ProductB1:public AbstractProductB
{
public:
ProductB1();
~ProductB1();
void Interact(AbstractProductA*);
};
void ProductB1::ProductB1(void) {Print(" Product B1 constructed.");}
void ProductB1::~ProductB1(void) {Print(" Product B1 destructed.");}
void ProductB1::Interact(AbstractProductA*p) {Print(" Product B1: ",&this," interacts with Product A: ",p);}
//--------------------------------------------------------------------
class ProductB2:public AbstractProductB
{
public:
ProductB2();
~ProductB2();
void Interact(AbstractProductA*);
};
void ProductB2::ProductB2(void) {Print(" Product B2 constructed.");}
void ProductB2::~ProductB2(void) {Print(" Product B2 destructed.");}
void ProductB2::Interact(AbstractProductA*p) {Print(" Product B2: ",&this," interacts with Product A: ",p);}
//--------------------------------------------------------------------
class Factory1:public AbstractFactory
{
public:
Factory1();
~Factory1();
AbstractProductA* CreateProductA();
AbstractProductB* CreateProductB();
};
//---
void Factory1::Factory1(void) {Print("Factory 1 constructed.");}
void Factory1::~Factory1(void) {Print("Factory 1 destructed.");}
AbstractProductA* Factory1::CreateProductA(void) {return new ProductA1;}
AbstractProductB* Factory1::CreateProductB(void) {return new ProductB1;}
//--------------------------------------------------------------------
class Factory2:public AbstractFactory
{
public:
Factory2();
~Factory2();
AbstractProductA* CreateProductA();
AbstractProductB* CreateProductB();
};
//---
void Factory2::Factory2(void) {Print("Factory 2 constructed.");}
void Factory2::~Factory2(void) {Print("Factory 2 destructed.");}
AbstractProductA* Factory2::CreateProductA(void) {return new ProductA1;}
AbstractProductB* Factory2::CreateProductB(void) {return new ProductB1;}
//--------------------------------------------------------------------
class FactoryClient
{
public:
void Run();
void Switch(AbstractFactory*);
FactoryClient(AbstractFactory*);
~FactoryClient();
protected:
AbstractProductA* apa;
AbstractProductB* apb;
AbstractFactory* factory;
void Delete();
};
//---
void FactoryClient::FactoryClient(AbstractFactory* af) {Switch(af);}
void FactoryClient::~FactoryClient(void) {Delete();}
void FactoryClient::Run(void) {apb.Interact(apa);}
void FactoryClient::Delete(void) {delete apa; delete apb; delete factory;}
void FactoryClient::Switch(AbstractFactory *af)
{
Delete();
factory=af;
apa=factory.CreateProductA();
apb=factory.CreateProductB();
}
//--------------------------------------------------------------------
class Client:public ClientExample {public:string Output(); void Run();};
string Client::Output(void) {return __FUNCTION__;}
void Client::Run()
{
FactoryClient client(new Factory1);
client.Run();
client.Switch(new Factory2);
client.Run();
}
}
//+---------------------------------------------------------------------------------------------------------+
//| Output |
//+---------------------------------------------------------------------------------------------------------+
//Creational::AbstractFactory::Client::Output
//Factory 1 constructed.
// Product A1 constructed.
// Product B1 constructed.
// Product B1: 126877696 interacts with Product A: 125829120
//Factory 2 constructed.
// Product A1 destructed.
// Product B1 destructed.
//Factory 1 destructed.
// Product A2 constructed.
// Product B2 constructed.
// Product B2: 130023424 interacts with Product A: 128974848
// Product A2 destructed.
// Product B2 destructed.
//Factory 2 destructed.
#29978LibrariesMetaTrader 5👁 3640 views
Design patterns - Abstract Factory
D
Author
DMITRII PECHERITSAPublished date
Jul 15, 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 →