Creator mode

1, Introduction to builder mode

1. Introduction to builder mode

The builder pattern separates the construction and representation of a complex object, so that the same construction process can create different representations.

Builder mode and abstract factory mode are similar in function. They are used to create large and complex objects. The difference is: Builder mode emphasizes creating objects step by step, and different result objects can be obtained through the same creation process. Generally speaking, objects in builder mode are not returned directly. In the abstract factory pattern, objects are returned directly. The abstract factory pattern emphasizes providing a same interface for creating multiple interdependent objects.

The main function of the builder mode is to arrange the calling sequence of basic methods, that is, the assembly sequence of objects, while the factory method focuses on creation. What object should create an object, and the assembly sequence is not his concern.

The characteristics of the builder mode are as follows:

A. builder mode is to encapsulate the creation process of a complex object. Customers only need to know that they can use the object name or type to get a complete object instance without paying attention to the specific creation process of the object.

B. The Builder mode separates the creation process of the object from the object itself, so that the details depend on abstraction and comply with the principle of dependency inversion. You can use the same creation process to create different product objects.

2. Builder mode role

Commander Director: build an interface using the builder object. The Construct function completes the construction of the object by calling the interface function of the specific Builder (the assembly process of different parts is the same, but different construction methods will have different representations (how to build is determined according to the actual type of builder, that is, polymorphism). The role of commander is to isolate the production process of customers and objects, and be responsible for controlling the production process of product objects. The commander is responsible for calling the appropriate builder to build the product. Generally, it does not depend on the product class. The builder class directly interacts with the commander class. In general, the commander column is used to encapsulate the volatile parts of the program.

Builder Builder: defines the abstraction of the process of creating an object and provides interfaces for building different components. buildPartA, buildPartB and buildPartC are function interfaces for building different parts of an object, which are specifically implemented by the derived classes concretebuilder m and concretebuilder n. Set up products; Returns the assembled product.

Product: generally, it is a complex object, that is, the process of creating an object is complex, and there is usually a large amount of code. In actual programming, product classes can be composed of an abstract class and its different implementations, or multiple abstract classes and their implementations.

An object may have different components. The creation of different parts will have different representations in the creation of objects, but the assembly methods between various parts are the same. For example, a bicycle is composed of wheels, seats, etc. (different components of an object), and different brands produce different products (different construction methods). Although different brands build different bicycles, the construction process is the same. The assembly method of each component is fixed in the Director::Construct function. When the specific component is assembled, it is implemented by the derived class of Builder.

The implementation of Builder mode is based on several object-oriented design principles:

A. extract the changed part to form a base class and corresponding interface function. What will not change is that PartA and PartB will be created, and what will change is different creation methods. Therefore, extract the Builder base class and buildparta and buildpartb interface functions.

B. aggregate the base class that will change in the way of aggregation, that is, Director aggregates the pointer of Builder class.

Two different construction details are defined through two derived classes, ConcreteBuilderM and ConcreteBuilderN (the construction steps are the same and determined by the Construct function). The objects built through the two derived classes have different external properties or functions, It is determined by the construction methods (BuildPartA, BuildPartB, BuildPartC) in their respective Builder derived classes.

3. Advantages and disadvantages of builder mode

Advantages:

A. the encapsulation of the builder mode is very good. Using the builder mode can effectively encapsulate changes. In the scenario of using the builder mode, the general product class and builder class are relatively stable. Therefore, encapsulating the main business logic in the commander class can achieve better stability as a whole.

B. The Builder mode is easy to expand. If there are new requirements, it can be completed by implementing a new builder class. Basically, there is no need to modify the code that has passed the test before, so there will be no risk to the original function.

C. decompose the creation steps of complex products into different methods to make the creation process clearer and enable us to more accurately control the generation process of complex objects.

D. separate the product creation process from the product itself. You can use the same creation process to get different products.

E. each specific builder is relatively independent and has nothing to do with other specific builders. Therefore, it is convenient to replace or add new specific builders. Users can get different product objects by using different specific builders.

Disadvantages:

A. the steps (algorithms) required to build the product should not change dramatically, preferably unchanged, which affects the flexibility.

B. if the internal changes of the product are complex, it may lead to the need to define many specific builder classes to realize the internal complex changes, resulting in the system becoming very large.

4. Builder mode usage scenario

Usage scenario of builder mode:

A. the products created by the builder mode generally have more in common, and their components are similar. If there are great differences between products, the builder mode is not suitable for use, so its scope of use is limited.
B. When the algorithm for creating complex objects should be independent of the components of the object and the assembly method.

C. when the construction process must allow different representations of each part of the constructed object.

D. the product object to be generated has a complex internal structure, and the product object usually contains multiple member attributes.

2, Builder mode implementation

The implementation of Builder mode is based on the following object-oriented design principles:

A. extract the changed part to form a base class and corresponding interface function. What will not change is that PartA, PartB and PartC will be created. What will change is different creation methods. Therefore, the Builder base class and buildPartA, buildPartB and buildPartC interface functions will be extracted.

B. the base class that will change is aggregated by aggregation, that is, the Director aggregates the pointer of the Builder class.

Two different construction details are defined through two derived classes, ConcreteBuilderM and ConcreteBuilderN (the construction steps are the same and determined by the Construct function). The objects built through the two derived classes have different external properties or functions, It is determined by the construction methods (BuildPartA, BuildPartB, BuildPartC) in their respective Builder derived classes.

Product.h File:
#ifndef PRODUCT_H
#define PRODUCT_H
#include <string>
#include <iostream>
using namespace std;
 
class Product
{
public:
    Product();
    ~Product();
    void setPartA(const string& s);
    void setPartB(const string& s);
    void setPartC(const string& s);
private:
    string m_PartA;
    string m_PartB;
    string m_PartC;
};
 
#endif // PRODUCT_H
Product.cpp File:
#include "Product.h"
 
Product::Product()
{
}
 
Product::~Product()
{
 
}
 
void Product::setPartA(const string& s)
{
    m_PartA = s;
}
 
void Product::setPartB(const string& s)
{
    m_PartB = s;
}
 
void Product::setPartC(const string& s)
{
    m_PartC = s;
}
Director.h File:
//Using builder to build products, the process of building products is the same, but different builders have different implementations
// Different implementations are implemented through different Builder derived classes. There is a Builder pointer, which can be used to realize polymorphic calls
 
#ifndef DIRECTOR_H
#define DIRECTOR_H
#include "Builder.h"
 
class Director
{
public:
    Director(Builder* pBuilder);
    ~Director();
 //The Construct function defines the whole construction process of an object. The assembly methods between different parts are the same. First, build PartA and then PartB, but there will be different representations according to different builders 
    void construct();
private:
    Builder* m_pBuilder;
};
 
#endif // DIRECTOR_H
 
Director.cpp File:
#include "Director.h"
 
Director::Director(Builder* pBuilder)
{
    m_pBuilder = pBuilder;
}
 
Director::~Director()
{
 
}
 
void Director::construct()
{
    m_pBuilder->buildPartA();
    m_pBuilder->buildPartB();
    m_pBuilder->buildPartC();
 
}
Builder.h File:
//Abstract the Builder base class and define the creation interfaces of different parts
#ifndef BUILDER_H
#define BUILDER_H
#include "Product.h"
 
class Builder
{
public:
    Builder();
    virtual ~Builder();
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product* getProduct() = 0;
};
 
#endif // BUILDER_H
Builder.cpp File:
#include "Builder.h"
 
Builder::Builder()
{
}
 
Builder::~Builder()
{
}
ConcreteBuilderM.h File:
//Partierbuilder class and partierbuilder function derived from partierbuilder
#ifndef CONCRETEBUILDERM_H
#define CONCRETEBUILDERM_H
#include "Builder.h"
 
class ConcreteBuilderM : public Builder
{
public:
    ConcreteBuilderM();
    ~ConcreteBuilderM();
    virtual void buildPartA();
    virtual void buildPartB();
    virtual void buildPartC();
    virtual Product* getProduct();
private:
    Product* m_pProduct;
};
 
#endif // CONCRETEBUILDERM_H
 
ConcreteBuilderM.cpp File:
#include "ConcreteBuilderM.h"
 
ConcreteBuilderM::ConcreteBuilderM()
{
    m_pProduct = new Product();
    cout << "ConcreteBuilderM" << endl;
}
 
ConcreteBuilderM::~ConcreteBuilderM()
{
    delete m_pProduct;
    m_pProduct = NULL;
}
 
void ConcreteBuilderM::buildPartA()
{
    m_pProduct->setPartA("A");
    cout << "ConcreteBuilderM::buildPartA()"<< endl;
 
}
 
void ConcreteBuilderM::buildPartB()
{
    m_pProduct->setPartB("B");
    cout << "ConcreteBuilderM::buildPartB()"<< endl;
 
}
 
void ConcreteBuilderM::buildPartC()
{
    m_pProduct->setPartC("C");
    cout << "ConcreteBuilderM::buildPartC()"<< endl;
 
}
 
Product* ConcreteBuilderM::getProduct()
{
    return m_pProduct;
 
}
ConcreteBuilderN.h File:
//The derived class of Builder implements the interface functions of BuilderPartA, BuilderPartB and BuildPartC 
#ifndef CONCRETEBUILDERN_H
#define CONCRETEBUILDERN_H
#include "Builder.h"
 
class ConcreteBuilderN : public Builder
{
public:
    ConcreteBuilderN();
    ~ConcreteBuilderN();
    virtual void buildPartA();
    virtual void buildPartB();
    virtual void buildPartC();
    virtual Product* getProduct();
private:
    Product* m_pProduct;
};
 
#endif // CONCRETEBUILDERN_H
 
ConcreteBuilderN.cpp File:
#include "ConcreteBuilderN.h"
 
ConcreteBuilderN::ConcreteBuilderN()
{
    m_pProduct = new Product();
    cout << "ConcreteBuilderN" << endl;
}
 
ConcreteBuilderN::~ConcreteBuilderN()
{
    delete m_pProduct;
    m_pProduct = NULL;
}
 
void ConcreteBuilderN::buildPartA()
{
    m_pProduct->setPartA("A");
    cout << "ConcreteBuilderN::buildPartA()"<< endl;
 
}
 
void ConcreteBuilderN::buildPartB()
{
    m_pProduct->setPartB("B");
    cout << "ConcreteBuilderN::buildPartB()"<< endl;
 
}
 
void ConcreteBuilderN::buildPartC()
{
    m_pProduct->setPartC("C");
    cout << "ConcreteBuilderN::buildPartC()"<< endl;
 
}
 
Product* ConcreteBuilderN::getProduct()
{
    return m_pProduct;
 
}
Main.cpp File:
#include <iostream>
#include "Director.h"
#include "ConcreteBuilderM.h"
#include "ConcreteBuilderN.h"
 
using namespace std;
 
int main()
{
    Director* director1 = new Director(new ConcreteBuilderM());
    director1->construct();
 
    Director* director2 = new Director(new ConcreteBuilderN());
    director2->construct();
 
    delete director1;
    delete director2;
    return 0;
}

Keywords: Design Pattern

Added by warptwist on Fri, 18 Feb 2022 05:32:56 +0200