Reference: refactoringguru. Cn/design – patt…

intentions

Generator pattern is a creative design pattern that allows you to create complex objects in steps. This pattern allows you to generate objects of different types and forms using the same creation code.

The problem

Suppose you need to create a complex object, such as a Car object.

Usually, to make an ordinary car, you need tires, Windows, chassis, engine and other equipment. But if we were to build a luxury car, in addition to these things, we would probably have GPS, anti-lock braking system, AV equipment and so on. What do you do when you create such complex objects? There are two common practices:

  1. extensionCarThe base class,Create a subclass for each possible object. The disadvantage is that this will result in a large number of subclasses. Any additional parameters make the hierarchy more complex.
  2. inCarCreate one in the base class that contains all possible parametersSuperconstructorAnd use it to controlCarObject. The downside is that most of the arguments may not be used, and this will make the constructor call complicated.

The solution

The generator pattern suggests pulling the object construction code out of the production class and putting it in a separate object called the generator.

This pattern divides the object construction process into a set of steps. Each time you create an object, you need to perform a series of steps through the generator object. Which steps are invoked depends on what kind of object you are creating. If you create an ordinary car, you may only need to install tires, Windows, chassis and other steps.

** Some construction steps may require different implementations when different forms of products need to be created. ** For example, if you want to create two different versions of a tank and a car, the step of installing a tire would definitely require a different implementation. Because tanks have tracks and cars have tires. In this case, you need several different generator objects that implement the same set of creation steps in different ways. These generators are then used to generate objects of different types during the creation process.

You can further extract the series of generator step calls used to create the product into a separate master class. The master class defines the order in which the creation steps are executed, while the generator provides the implementation of those steps. ** From the client side, the master class completely hides product construction details. The client simply associates a generator with the master class, then uses the master class to construct the product, and gets the build results from the generator.

The generator pattern is used to propose a solution to the problem, and how to reuse the same object construction code to generate different types of products is tested. The class diagram is as follows:

Generator pattern structure

  1. Builder: Generator interface that declares product construction steps common to all type generators.
  2. Concrete Builders: concrete generator that provides different implementations of the construction process. Concrete generators can construct products that do not follow a generic interface, as in the questionCarandManual, the two do not follow the same interface, but are related (the construction steps are similar). ** Therefore, concrete generators generally need to provide their own means of obtaining products. ** However, if all products follow the same interface, it is safe to add methods to get products into the Builder interface.
  3. Products: indicates the final generated product object.
  4. Director: The Director class that defines the order in which construction steps are invoked so that you can create and reuse specific product configurations. In cases where all products follow the same interface, products can be obtained directly through the master class. Otherwise, the client should get the product through the generator.
  5. Client: Associates a generator object with a master class. In general, only one correlation is required through the parameters of the main class constructor.

Code implementation of the problem

#include<iostream>
#include<string>
using namespace std;

// It only makes sense to use the generator pattern if the product is complex and requires detailed configuration. The next two
// Although the products do not have the same interface, they are interrelated.
class Car {
public:
	int seats;
	string engine;
	bool GPS;
	bool trip_computer;
public:
	void show(a) {
		cout << "seats:" << this->seats << endl;
		cout << "engine:" << this->engine << endl;
		cout << "GPS:" << this->GPS << endl;
		cout << "trip_computer:" << this->trip_computer << endl; }};class Manual {
public:
	int seats;
	string engine;
	bool GPS;
	bool trip_computer;
public:
	void describe(a) {
		cout << "This car has it." << this->seats << "One seat" << endl;
		if(! engine.empty())
			cout << "Engine model is :" << this->engine << endl;
		else
			cout << "No engine installed." << endl;

		if (GPS)
			cout << "This car is equipped with GPS." << endl;
		else
			cout<< "This car is not equipped with GPS." << endl;

		if (trip_computer)
			cout << "This bus carries a travel computer." << endl;
		else
			cout << "No travel computer on this bus."<< endl; }};The generator interface declares methods for creating different parts of a product object.
class Builder {
public:
	~Builder() {}virtual void reset(a) = 0;
	virtual void set_seats(int num) = 0;
	virtual void set_engine(string engine) = 0;
	virtual void set_tripComputer(bool ans) = 0;
	virtual void set_GPS(bool ans) = 0;
};

// A concrete generator class will follow the generator interface and provide a concrete implementation of the build step. It might be in your program
// There are several variants of generators implemented in different ways.
class CarBuilder : public Builder {
private:
	// A new generator instance must contain an empty product object to be used during subsequent assembly.
	Car* car;
public:
	CarBuilder() {
		this->reset(a); }The reset method clears the object being generated.
	virtual void reset(a) {
		this->car = new Car(a); }// All build steps interact with the same product instance.
	virtual void set_seats(int num) {
		this->car->seats = num;
	}
	virtual void set_engine(string engine) {
		this->car->engine = engine;
	}
	virtual void set_tripComputer(bool ans) {
		this->car->trip_computer = ans;
	}
	virtual void set_GPS(bool ans) {
		this->car->GPS = ans;
	}

	// The concrete generator needs to provide its own method to get the result. This is because different types of generators are possible
	// Create completely different products that do not follow the same interface. So it's not in the generator interface
	Declare these methods (at least in statically typed programming languages).
	//
	Usually after the generator instance returns the result to the client, they should be ready to generate another product
	/ / preparation. So generator instances are usually at the end of the 'getProduct' method body
	// Call the reset method. This behavior is not required, however, and you can have the generator wait for the client to clear up
	// Call the reset method to process the previous result.
	Car* get_product(a) {
		Car* result = this->car;
		this->reset(a);returnresult; }};class ManaualBuilder : public Builder {
private:
	Manual* man;
public:
	~ManaualBuilder() {}ManaualBuilder() {
		this->reset(a); }virtual void reset(a) {
		this->man = new Manual(a); }virtual void set_seats(int num) {
		this->man->seats = num;
	}
	virtual void set_engine(string engine) {
		this->man->engine = engine;
	}
	virtual void set_tripComputer(bool ans) {
		this->man->trip_computer = ans;
	}
	virtual void set_GPS(bool ans) {
		this->man->GPS = ans;
	}

	Manual* get_product(a) {
		Manual* result = this->man;
		this->reset(a);returnresult; }};// The supervisor is only responsible for executing the build steps in a specific order. When it builds products according to specific steps or configurations
// Can be very helpful. Because the client has direct control over the generator, the master class is technically merged
// Not required.
class Director {
private:
	Builder* builder;
public:
	// The supervisor can interact with any generator instance passed to it by the client code. The client can pass
	// Change the final type of the newly assembled product in this way.
	void set_builder(Builder* builder) {
		this->builder = builder;
	}
	// The director can create multiple product variants using the same build steps.
	void construct_sports_car(a) {
		builder->reset(a); builder->set_seats(2);
		builder->set_engine("HEXO1.0");
		builder->set_GPS(true);
		builder->set_tripComputer(true);
	}

	void construct_SUV(a) {
		builder->reset(a); builder->set_seats(4);
		builder->set_engine("HEXO2.0");
		builder->set_GPS(true); }};// The client code creates the generator object and passes it to the supervisor, which then performs the construction process. The final result
// Will need to be retrieved from the generator object.
void ClientCode(Director* director) {
	CarBuilder *car_builder = new CarBuilder(a); director->set_builder(car_builder);
	cout << "Build a sports car." << endl;
	director->construct_sports_car(a);// The final product usually needs to be fetched from the generator object because the supervisor does not know the specific generator and
	// The product exists and does not depend on it.
	Car* p_car = car_builder->get_product(a); p_car->show(a);delete p_car;

	cout << endl;

	ManaualBuilder *man_builder = new ManaualBuilder(a); director->set_builder(man_builder);
	cout << "Create a sports car manual." << endl;
	director->construct_sports_car(a); Manual *p_man = man_builder->get_product(a); p_man->describe(a);delete p_man;

	delete car_builder;
}

int main(a) {
	Director* director = new Director(a);ClientCode(director);
	delete director;
	return 0;
}
Copy the code

Advantages and disadvantages of this model

  1. advantages
    • You can create objects step by step, defer the creation step, or run the creation step recursively.
    • You can reuse the same manufacturing code when creating different forms of products.
    • Consistent with the principle of single responsibility. You can separate complex construction code from the business logic of the product.
  2. disadvantages
    • Because this pattern requires multiple new classes, the overall complexity of the code increases.