[C + + design mode] builder mode

Posted by Hades on Mon, 21 Feb 2022 03:47:33 +0100

***

  • Advantages of builder mode:
    • In the builder mode, the client does not need to know the internal composition details of the product, and separates the product itself from the product creation process, so that the same creation process can create different product objects;
    • Different builders are independent of each other without any chain, which is convenient for replacement.
  • Disadvantages of builder mode:
    • The products created by the builder mode generally have more in common and their components are similar. If there are great differences between products, it is not suitable to use the builder mode, so its scope of use is limited.
    • If the internal changes of the product are complex, it may lead to the need to define many specific builder classes to realize this change, resulting in a huge system
  • Applicable environment:
    • The product object to be generated has a complex internal structure (usually contains multiple member variables);
    • The internal attributes of the product object have a certain generation order;
    • The same creation process applies to many different products.

1, Builder mode

Builder pattern: separate the construction of a complex object from its representation, so that the same construction process can create different representations. For example, the process of building a house includes laying foundation, building walls, installing doors and windows, etc., but different styles of houses can be built according to the different needs of users.

1.1 structure of builder mode

  • Abstract Builder: create an abstract interface specified by each part of a Product object;
  • Concrete Builder: implement the interface of AbstractBuilder, realize the specific construction method and assembly method of each component, and return the creation result.
  • Product: specific product object
  • Director: build an object using the Builder interface and arrange the construction process of complex objects. Generally, the client only needs to interact with the director, specify the Builder type, and then pass the specific Builder object into the director through the constructor or setter method. Its main function is to isolate the production process of customers and objects, and be responsible for controlling the production process of product objects.

1.2 examples of builder mode

Building a house:

2, Code

2.1 header file

(1) Define the product class House class, which has three attributes: florr, wall and root.
(2) Define two abstract constructors AbstractBuilder, whose constructor is to create a new House instance object, and then there are four pure virtual functions for building walls and floors. Rewrite the pure virtual function in the later concrete builder class.
(3) Define the Director class, which is the most important and challenging. It also contains AbstractBuilder object, House type method for encapsulating the assembly process (the result returns the construction result) and setBuilder method (the parameter is AbstractBuilder *iBuilder, but we can pass in subclass object pointer, such as the object pointer of specific builder A, which uses polymorphism).

#include<string>
using namespace std;

//Product House
class House{
public:
	//Constructor
	House(){}
	void setFloor(string iFloor){
		this->floor = iFloor;
	}
	void setWall(string iWall){
		this->wall = iWall;
	}
	void setRoof(string iRoof){
		this->roof = iRoof;
	}
	//Print House information
	void printfHouseInfo(){
		printf("Floor:%s\t\n", this->floor.c_str());
		printf("Wall:%s\t\n", this->wall.c_str());
		printf("Roof:%s\t\n", this->roof.c_str());
	}
private:
	string floor;
	string wall;
	string roof;
};

//Abstract builder AbstractBall
class AbstractBuilder{
public:
	AbstractBuilder(){
		house = new House();
	}
	//Abstract method:
	virtual void buildFloor() = 0;
	virtual void buildWall() = 0;
	virtual void buildRoof() = 0;
	//Pure virtual function, which is carried out in the specific builder
	virtual House *getHouse() = 0;
	//Instantiate the house object
	House *house;
};

//Concrete builder a
class ConcreteBuilderA :public AbstractBuilder{
public:
	ConcreteBuilderA(){
		printf("ConcreteBuilderA\n");
	}
	//Specific implementation method
	void buildFloor(){
		this->house->setFloor("Floor_A");
	}
	void buildWall(){
		this->house->setWall("Wall_A");
	}
	void buildRoof(){
		this->house->setRoof("Roof_A");
	}
	House *getHouse(){
		return this->house;
	}
};
 
//Concrete builder B
class ConcreteBuilderB :public AbstractBuilder{
public:
	ConcreteBuilderB(){
		printf("ConcreteBuilderB\n");
	}
	//Specific implementation method
	void buildFloor(){
		this->house->setFloor("Floor_B");
	}
	void buildWall(){
		this->house->setWall("Wall_B");
	}
	void buildRoof(){
		this->house->setRoof("Roof_B");
	}
	House *getHouse(){
		return this->house;
	}
};

//Commander
class Director{
public:
	Director(){}
	//Specific implementation method
	void setBuilder(AbstractBuilder *iBuilder){
		this->builder = iBuilder;
	}
    //Package assembly process and return construction results
	House *construct(){
		builder->buildFloor();
		builder->buildWall();
		builder->buildRoof();
		return builder->getHouse();
	}
private:
	AbstractBuilder *builder;
};

2.2 client code

#include "BuilderPattern.h"
 
int main(){
	//Abstract builder
	AbstractBuilder *builder;
	//Commander
	Director *director = new Director();
	//Product: House
	House *house;
 
	//Specify specific builder A
	builder = new ConcreteBuilderA();
	director->setBuilder(builder);
	house = director->construct();
	house->printfHouseInfo();
 
	//Specify specific builder B
	builder = new ConcreteBuilderB();
	director->setBuilder(builder);
	house = director->construct();
	house->printfHouseInfo();
 
	system("pause");
	return 0;
}

  • In the client, you only need to specify the specific builder and pass it to the commander as a parameter, and the result can be obtained through the commander. There is no need to care about the specific process and method of building House.
  • If you need to change the construction style, you only need to change the builder. There is a connection between different builders to facilitate replacement.
  • From the perspective of code optimization, in fact, we can directly put the construct method into the specific builder without the role of Director.

Topics: C++ Design Pattern