C + + design pattern builder pattern (the construction of complex objects is separated from their representation) the production process of different KFC roast chickens

Keywords: C++


reflection:
Why can KFC McDonald's fast food stand in China, a country with 5000 years of history? Why can't Chinese shredded pork with fish flavor become a popular fast food?
Because McDonald's KFC uses uniformly made fast food, which is equivalent to that the chef is a chef, and every restaurant in China has fish flavored shredded meat, but the chefs in every restaurant in China are different, and the taste of fish flavored shredded meat is also different. Because of this difference, we are not sure whether the fish flavored shredded meat in the restaurant we haven't eaten makes us want to eat, No matter which KFC store we are in, the hamburgers we eat have the same taste. As long as we like to eat, we can eat any one;
So fish flavored shredded pork depends on the chef. Think about the principles of design mode?
Dependency Inversion Principle: abstraction should not rely on details, but details should rely on abstraction. The result is very passive; KFC's workflow is equivalent to an abstract process (feeding, barbecue, spicy touch, etc.), and the details such as what ingredients to put and how long to bake depend on this abstract process;

This paper also involves two knowledge points

  • delete
    Before this article, I used the delete p1, p2, p3 format in my delete, but this is wrong because the above statement expresses: delete p1; p2; p3, so only p1 is deleted; In addition, in C + +, because the compiler is not responsible for deleting a pointer such as p1, only the heap memory space pointed to by p1 is recovered after the delete is executed, but the p1 pointer still exists. At this time, p1 has become a wild pointer. Therefore, after deleting p1, p1 needs to be deleted in the format of p1 = nullptr, so the p1 pointer cannot be accessed later
  • Destructor
    When a subclass inherits from the base class, a pointer object will be generated in the subclass, and this object must be recycled when the subclass is destructed, then the destructor of the base class must be defined as a virtual function, so that the pointer object in the subclass can be recycled in case of polymorphism
class A{
public: 
    virtual ~A(){} // Command 1
    virtual void getName(){};
};

class B : public A{
private:
    string name;
public:
    A * a = new A();
    B(string n): name(n){}
    ~B(){ // If command 1 is commented out, it will not run here
        delete a; a = nullptr;
        cout << "Deconstruction" << name <<endl;
    }
    void getName(){
        cout<< "name = "<< name <<endl;
    }
};

int main(int argc, char const *argv[])
{
    A * b1 = new B("b1");
    A * b2 = new B("b2");
    A * b3 = new B("b3");
    A * b4 = new B("b4");

    delete b1,b2,b3,b4;
    // b1->getName(); //  However, it can still compile successfully but run unsuccessfully. Segmentation fault (core dumped)
    b1 = nullptr;
    if(b1){
        cout << "b1 Not empty, have access to" <<endl;
        b1->getName();
    }
    cout << "Here's the serious way to delete different pointer objects" <<endl;
    delete b2, delete b3, delete b4; b2=b3=b4=nullptr;
    return 0;
}

1. Theoretical basis

Purpose:
Separating a complex build from its representation allows the same build process to create different representations.

Main solutions:
The main solution is that in software systems, sometimes we are faced with the creation of "a complex object", which is usually composed of sub objects of each part with a certain algorithm; Due to the change of requirements, each part of this complex object often faces drastic changes, but the algorithm that combines them is relatively stable.

When to use:
Some basic components do not change, and their combinations often change.

How to solve:
Separate change from invariance.

Key codes:
Builder: create and provide instances,
Director: manage the dependencies of built instances.

Application example:
1. Go to KFC, hamburger, coke, French fries, fried chicken wings, etc. are unchanged, and their combination changes frequently, generating the so-called "set meal".
2. StringBuilder in JAVA.

advantage:
1. The builder is independent and easy to expand. 2. Easy to control detail risk.

Disadvantages:
1. Products must have common ground and limited scope. 2. If the internal changes are complex, there will be many construction classes.

Usage scenario:
1. The object to be generated has a complex internal structure. 2. The internal properties of the object to be generated depend on each other.

matters needing attention:
The difference from the factory mode is that the builder mode pays more attention to the assembly sequence of parts.

2. Logic code


As shown in the figure above:

  • Builder is equivalent to making hamburger's abstract class and specifying the abstract interface for each part of the Product object
  • ConcreteBuilder is equivalent to the specific implementation of each detailed process of making hamburger
  • Director commander, build different hamburgers according to user needs
  • When do I need to use builder mode? It is used to create some complex objects. The construction order between internal constructions of these objects is usually stable, but the construction within objects usually faces complex changes
#include <iostream>
#include <algorithm>
#include <string.h>
#include <list>
using namespace std;

// Product category
class Product{
private:
    list<string> parts; // Create an assembly using a linked list
public:
    virtual ~Product(){}
    // Add product parts
    void Add(string part){
        parts.push_back(part);
    }

    void Show(){
        cout<< "Product creation ... " <<endl;
        for(auto &s : parts){
            cout << s <<endl;
        }
    }
};

// Builder class
class Builder{
public:
    virtual ~Builder(){}
    virtual void BuildPartA() = 0;
    virtual void BuildPartB() = 0;
    virtual Product *GetResult() = 0;
};

// Specific builder class
// Builder 1
class ConcreteBuilder1 : public Builder{
private:
    Product *product = new Product();
public:
    ~ConcreteBuilder1(){
        cout << "jjjj" <<endl;
        try {
            delete product; product = nullptr;
        }
        catch(const std::exception& e) {
            std::cerr << e.what() << '\n';
        }
    }
    void BuildPartA(){
        product->Add("parts A");
    }

    void BuildPartB(){
        product->Add("parts B");
    }

    Product* GetResult(){
        return product;
    }
};

// Builder 2
class ConcreteBuilder2 : public Builder{
private:
    Product *product = new Product();
public:
    ~ConcreteBuilder2(){
        cout << "Delete succeeded?? " <<endl;
        delete product; product = nullptr;
    }
    void BuildPartA(){
        product->Add("parts X");
    }

    void BuildPartB(){
        product->Add("parts Y");
    }

    Product* GetResult(){
        return product;
    }
};

// Conductor Director class
class Director{
public:
    ~Director(){
        cout << "delete Direct" <<endl;
    }
    void Construct(Builder *builder){
        builder->BuildPartA();
        builder->BuildPartB();
    }
};

int main(int argc, char const *argv[])
{
    Builder *b1 = new ConcreteBuilder1();
    Builder *b2 = new ConcreteBuilder2();

    Director *director = new Director();

    director->Construct(b1);
    Product *p1 = b1->GetResult();
    p1->Show();

    director->Construct(b2);
    Product *p2 = b2->GetResult();
    p2->Show();

    delete b1; b1 = nullptr;
    delete b2; b2 = nullptr;
    delete director; director = nullptr;
    // The following two will report errors because b1 and b2 have been destructed above
    // delete p1; p1 = nullptr;
    // delete p2; p2 = nullptr;
    // Note that the destructor of the Builder class here must be defined as virtual, otherwise the subclass instance cannot be deleted
    
    return 0;
}

3. Application

3.1 making hamburgers

three layers
product
builder
Commander
customer

// Product category
class Product{
private:
    list<string> parts; // Create an assembly using a linked list
public:
    virtual ~Product(){}
    // Add product parts
    void Add(string part){
        parts.push_back(part);
    }

    void Show(){
        cout<< "Product creation ... " <<endl;
        for(auto &s : parts){
            cout << s <<endl;
        }
    }
};

// Builder class
class Builder{
public:
    virtual ~Builder(){}
    virtual void BuildPartA() = 0;
    virtual void BuildPartB() = 0;
    virtual void BuildPartC() = 0;
    virtual Product *GetResult() = 0;
};

// Specific builder class
// Roast chicken construction
class ConcreteBuilderSJ : public Builder{
private:
    Product *product = new Product();
public:
    ~ConcreteBuilder1(){
        delete product; product = nullptr;
    }
    void BuildPartA(){
        product->Add("Fry for 10 hours");
    }

    void BuildPartB(){
        product->Add("Salty salt 20kg");
    }

    void BuildPartC(){
        product->Add("Mustard 1 kg");
    }
    Product* GetResult(){
        return product;
    }
};

// Builder Mustard Chicken
class ConcreteBuilderJMJ : public Builder{
private:
    Product *product = new Product();
public:
    ~ConcreteBuilder2(){
        cout << "Delete succeeded?? " <<endl;
        delete product; product = nullptr;
    }
    void BuildPartA(){
        product->Add("Fry for 1 hour");
    }

    void BuildPartB(){
        product->Add("Salt 2 kg");
    }

    void BuildPartC(){
        product->Add("Mustard 100 tons");
    }
    Product* GetResult(){
        return product;
    }
};

// Conductor Director class
class Director{
public:
    ~Director(){
        cout << "delete Direct" <<endl;
    }
    void Construct(Builder *builder){
        builder->BuildPartA();
        builder->BuildPartB();
        builder->BuildPartC();
    }
};

int main(int argc, char const *argv[])
{
    Builder *b1 = new ConcreteBuilderSJ(); // Roast chicken Chef
    Builder *b2 = new ConcreteBuilderJMJ(); // Mustard chicken Chef

    Director *director = new Director(); // Kitchen boss

    director->Construct(b1);  // The boss asked the cook to create a roast chicken 
    Product *p1 = b1->GetResult();// A roast chicken cook produces a roast chicken
    p1->Show(); // Roast chicken to customers

    director->Construct(b2);
    Product *p2 = b2->GetResult();
    p2->Show();

    delete b1; b1 = nullptr;
    delete b2; b2 = nullptr;
    delete director; director = nullptr;
    return 0;
}

Posted by smilesmita on Wed, 06 Oct 2021 20:00:17 -0700