345 lines
25 KiB
Plaintext
345 lines
25 KiB
Plaintext
/*********************************************************************
|
|
MQL5 Script
|
|
Copyright 2019, dmipec
|
|
792112@gmail.com
|
|
|
|
Classic Builder Programming Pattern
|
|
This pattern was published in the "Design Patterns: Elements of
|
|
Reusable Object-Oriented Software", 1st Edition, by Erich Gamma
|
|
(Author), Richard Helm (Author), Ralph Johnson (Author), John
|
|
Vlissides (Author), Grady Booch (Foreword). These authors are
|
|
collectively known as Gang of Four (GoF).
|
|
|
|
Structure is shown on a diagram
|
|
|
|
Intent
|
|
Separate the construction of a complex object from its
|
|
representation so that the same construction process can create
|
|
different representations.
|
|
|
|
Applicability
|
|
* the algorithm for creating a complex object should be independent
|
|
of the parts that make up the object and how they're assembled.
|
|
* the construction process must allow different representations for
|
|
the object that's constructed.
|
|
|
|
Participants
|
|
Builder
|
|
* specifies an interface for creating parts of a Product object.
|
|
Concrete Builder
|
|
* constructs and assembles parts of the product by implementing
|
|
the Builder interface.
|
|
* defines and keeps track of the representation it creates.
|
|
* provides an interface for retrieving the product.
|
|
Director
|
|
* constructs an object using the Builder interface;
|
|
Product
|
|
* represents the complex object under construction. Concrete
|
|
Builder builds the product's internal representation and defines
|
|
the process by which it's assembled.
|
|
* includes classes that define the constituent parts, including
|
|
interfaces for assembling the parts into the final result.
|
|
|
|
Collaborations (diagram)
|
|
* The client creates the Director object and configures it with the
|
|
desired Builder object.
|
|
Director notifies the builder whenever a part of the product should
|
|
be built.
|
|
* Builder handles requests from the director and adds parts to the
|
|
product.
|
|
* The client retrieves the product from the builder.
|
|
|
|
Consequences
|
|
It lets you vary a product's internal representation.
|
|
The Builder object provides the director with an abstract
|
|
interface for constructing the product. The interface lets the
|
|
builder hide the representation and internal structure of the
|
|
product. It also hides how the product gets assembled. Because
|
|
the product is constructed through an abstract interface, all
|
|
you have to do to change the product's internal representation
|
|
is define a new kind of builder.
|
|
It isolates code for construction and representation.
|
|
The Builder pattern improves modularity by encapsulating the way
|
|
a complex object is constructed and represented. Clients needn't
|
|
know anything about the classes that define the product's
|
|
internal structure; such classes don't appear in Builder's
|
|
interface. Each Builder contains all the code to create and
|
|
assemble a particular kind of product. The code is written once;
|
|
then different Directors can reuse it to build Product variants
|
|
from the same set of parts.
|
|
It gives you finer control over the construction process.
|
|
Unlike creational patterns that construct products in one shot,
|
|
the Builder pattern constructs the product step by step under
|
|
the director's control. Only when the product is finished does
|
|
the director retrieve it from the builder. Hence the Builder
|
|
interface reflects the process of constructing the product more
|
|
than other creational patterns. This gives you finer control
|
|
over the construction process and consequently the internal
|
|
structure of the resulting product.
|
|
|
|
Implementation
|
|
* Typically there's an abstract Builder class that defines an
|
|
operation for each component that a director may ask it to create.
|
|
The operations do nothing by default. A ConcreteBuilder class
|
|
overrides operations for components it's interested in creating.
|
|
* Here are other implementation issues to consider:
|
|
Assembly and construction interface.
|
|
Builders construct their products in step-by-step fashion.
|
|
Therefore the Builder class interface must be general enough
|
|
to allow the construction of products for all kinds of
|
|
concrete builders. A key design issue concerns the model for
|
|
the construction and assembly process. A model where the
|
|
results of construction requests are simply appended to the
|
|
product is usually sufficient. But sometimes you might need
|
|
access to parts of the product constructed earlier. In that
|
|
case, the builder would return child nodes to the director,
|
|
which then would pass them back to the builder to build the
|
|
parent nodes.
|
|
Why no abstract class for products?
|
|
In the common case, the products produced by the concrete
|
|
builders differ so greatly in their representation that there
|
|
is little to gain from giving different products a common
|
|
parent class. Because the client usually configures the
|
|
director with the proper concrete builder, the client is in
|
|
a position to know which concrete subclass of Builder is in
|
|
use and can handle its products accordingly.
|
|
Empty methods as default in Builder.
|
|
In C++, the build methods are intentionally not declared pure
|
|
virtual member functions. They're defined as empty methods
|
|
instead, letting clients override only the operations they're
|
|
interested in.
|
|
|
|
Code output
|
|
Construction in progress...
|
|
Part A built
|
|
Part B built
|
|
Part C built
|
|
Delivering finished 'Real Product'
|
|
This 'Real Product' is made of:
|
|
Part A
|
|
Part B
|
|
Part C
|
|
*/
|
|
/* import generic object array from the standard MQL library */
|
|
#include <Generic\ArrayList.mqh>
|
|
/*********************************************************************
|
|
Interface for building blocks-objects of a complex abstract product
|
|
*/
|
|
interface I_Part {
|
|
string Id();
|
|
};
|
|
/*********************************************************************
|
|
Part A
|
|
*/
|
|
class C_PartA: public I_Part {
|
|
public:
|
|
string Id();
|
|
};
|
|
/*********************************************************************
|
|
Part B
|
|
*/
|
|
class C_PartB: public I_Part {
|
|
public:
|
|
string Id();
|
|
};
|
|
/*********************************************************************
|
|
Part C
|
|
*/
|
|
class C_PartC: public I_Part {
|
|
public:
|
|
string Id();
|
|
};
|
|
/*********************************************************************
|
|
Abstract Product (Interface)
|
|
* includes common tools for handling the product's parts container
|
|
*/
|
|
class A_Product {
|
|
protected:
|
|
CArrayList<I_Part*> m_parts;
|
|
public:
|
|
~A_Product();
|
|
virtual string Id() = 0;
|
|
void Display();
|
|
void Add(I_Part *part);
|
|
protected:
|
|
void Clear(CArrayList<I_Part*>&list);
|
|
};
|
|
/*********************************************************************
|
|
Product
|
|
* represents the complex object under construction. Concrete
|
|
Builder builds the product's internal representation and defines
|
|
the process by which it's assembled.
|
|
* includes classes that define the constituent parts, including
|
|
interfaces for assembling the parts into the final result.
|
|
*/
|
|
class C_Product: public A_Product {
|
|
public:
|
|
string Id();
|
|
};
|
|
/*********************************************************************
|
|
Builder
|
|
* specifies an interface for creating parts of a Product object.
|
|
*/
|
|
interface I_Builder {
|
|
void BuildPartA();
|
|
void BuildPartB();
|
|
void BuildPartC();
|
|
A_Product *GetResult();
|
|
};
|
|
/*********************************************************************
|
|
Concrete Builder
|
|
* constructs and assembles parts of the product by implementing
|
|
the Builder interface.
|
|
* defines and keeps track of the representation it creates.
|
|
* provides an interface for retrieving the product.
|
|
*/
|
|
class C_Builder: public I_Builder {
|
|
protected:
|
|
A_Product *m_product;
|
|
public:
|
|
C_Builder();
|
|
void BuildPartA();
|
|
void BuildPartB();
|
|
void BuildPartC();
|
|
A_Product *GetResult();
|
|
};
|
|
/*********************************************************************
|
|
Director
|
|
* constructs an object using the Builder interface;
|
|
*/
|
|
class C_Director {
|
|
protected:
|
|
I_Builder *m_builder;
|
|
public:
|
|
C_Director(I_Builder *builder);
|
|
void Construct();
|
|
};
|
|
/*********************************************************************
|
|
* Client:
|
|
*/
|
|
void OnStart()
|
|
{
|
|
/* The client creates the Director object and configures it with
|
|
the desired Builder object. */
|
|
C_Builder *builder = new C_Builder;
|
|
C_Director director(builder);
|
|
|
|
/* Director notifies the builder whenever a part of the product
|
|
should be built.
|
|
* Builder handles requests from the director and adds parts to
|
|
the product. */
|
|
director.Construct();
|
|
|
|
/* The client retrieves the product from the builder. */
|
|
C_Product *product = builder.GetResult();
|
|
product.Display();
|
|
|
|
delete product;
|
|
delete builder;
|
|
}
|
|
|
|
/*********************************************************************
|
|
Class methods section
|
|
*/
|
|
/**********************************************************************/
|
|
void C_Director::C_Director(I_Builder *builder)
|
|
{
|
|
m_builder = builder;
|
|
}
|
|
/**********************************************************************/
|
|
void C_Director::Construct()
|
|
{
|
|
Print("Construction in progress...");
|
|
m_builder.BuildPartA();
|
|
m_builder.BuildPartB();
|
|
m_builder.BuildPartC();
|
|
}
|
|
/**********************************************************************/
|
|
void C_Builder::C_Builder(void)
|
|
{
|
|
m_product = new C_Product;
|
|
}
|
|
/**********************************************************************/
|
|
void C_Builder::BuildPartA()
|
|
{
|
|
m_product.Add(new C_PartA);
|
|
Print(" Part A built");
|
|
}
|
|
/**********************************************************************/
|
|
void C_Builder::BuildPartB()
|
|
{
|
|
m_product.Add(new C_PartB);
|
|
Print(" Part B built");
|
|
}
|
|
/**********************************************************************/
|
|
void C_Builder::BuildPartC()
|
|
{
|
|
m_product.Add(new C_PartC);
|
|
Print(" Part C built");
|
|
}
|
|
/**********************************************************************/
|
|
A_Product *C_Builder::GetResult()
|
|
{
|
|
PrintFormat("Delivering finished '%s'", m_product.Id());
|
|
return m_product;
|
|
}
|
|
/**********************************************************************/
|
|
void A_Product::~A_Product(void)
|
|
{
|
|
Clear(m_parts);
|
|
}
|
|
/**********************************************************************/
|
|
void A_Product::Add(I_Part *part)
|
|
{
|
|
if(!m_parts.Contains(part)) {
|
|
m_parts.Add(part);
|
|
}
|
|
}
|
|
/**********************************************************************/
|
|
void A_Product::Display()
|
|
{
|
|
PrintFormat("This '%s' is made of:", Id());
|
|
I_Part *e;
|
|
int total = m_parts.Count();
|
|
for(int i = 0; i < total; i++) {
|
|
m_parts.TryGetValue(i, e);
|
|
PrintFormat(" %s", e.Id());
|
|
}
|
|
}
|
|
/**********************************************************************/
|
|
void A_Product::Clear(CArrayList<I_Part*>&list)
|
|
{
|
|
I_Part *e;
|
|
int total = list.Count();
|
|
for(int i = 0; i < total; i++) {
|
|
list.TryGetValue(i, e);
|
|
if(CheckPointer(e) == POINTER_DYNAMIC) delete e;
|
|
}
|
|
list.Clear();
|
|
}
|
|
/**********************************************************************/
|
|
string C_Product::Id(void)
|
|
{
|
|
return "Real Product";
|
|
}
|
|
/**********************************************************************/
|
|
string C_PartA::Id()
|
|
{
|
|
return "Part A";
|
|
}
|
|
/**********************************************************************/
|
|
string C_PartB::Id()
|
|
{
|
|
return "Part B";
|
|
}
|
|
/**********************************************************************/
|
|
string C_PartC::Id()
|
|
{
|
|
return "Part C";
|
|
}
|
|
|
|
/*********************************************************************
|
|
* The code file was formatted with Stroustrup C++ style (MetaEditor >
|
|
Tools > Options > Styler). Use Alt-G/M/Arrows to navigate.
|
|
*/
|