设计模式——建造者模式(生成器模式)

建造者模式(生成器模式)

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图
用了建造者模式,那么用户就只需要指定需要构建的类型就可以得到它们,而具体构造的细节和过程不需要知道
在这里插入图片描述

概括地说,Builder是为创建一个Product对象的各个部件指定的抽象接口
而ConcreteBuilder是具体的建造者,实现Builder接口,构造和装配各个部件,Product是具体的产品
Director是指挥者,是构建一个使用Builder接口的对象。

  • 什么时候需要用到建造者模式?
    当我们需要创建一些复杂的对象,这些对象内部构建间的顺序通常是稳定的,但是对象内部的构建通常面临着复杂的变化

  • 实现方法

    1. 清晰地定义通用步骤, 确保它们可以制造所有形式的产品。 否则你将无法进一步实施该模式。
    2. 在基本生成器接口中声明这些步骤。
    3. 为每个形式的产品创建具体生成器类, 并实现其构造步骤。
    4. 考虑创建主管类。 它可以使用同一生成器对象来封装多种构造产品的方式。
    5. 客户端代码会同时创建生成器和主管对象。 构造开始前, 客户端必须将生成器对象传递给主管对象。 通常情况下, 客户端只需调用主管类构造函数一次即可。 主管类使用生成器对象完成后续所有制造任务。 还有另一种方式, 那就是客户端可以将生成器对象直接传递给主管类的制造方法。
    6. 只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。 否则, 客户端应当通过生成器获取构造结果。

基本代码如下

#include <iostream>
#include <vector>
#include <string>

using std::cout;

// 当产品非常复杂并且需要大量配置的时候,使用生成器模式非常有意义
// 各种构造器的结果可能并不总是遵循相同的接口

class Product1
{
public:
    std::vector<std::string> parts_;

    void ListParts() const
    {
        cout << "Product parts: ";
        for (size_t i = 0; i < parts_.size(); i++)
        {
            if (parts_[i] == parts_.back())
            {
                cout << parts_[i];
            }
            else
            {
                cout << parts_[i] << ", ";
            }
        }
        cout << "\n\n";
    }
};

// Builder 接口指定了创建 Product 对象不同部分的方法。
class Builder
{
public:
    virtual ~Builder(){};
    virtual void ProducePartA() const = 0;
    virtual void ProducePartB() const = 0;
    virtual void ProducePartC() const = 0;
};

// ConcreteBuilder 类遵循Builder类提供的接口,并提供建造步骤的具体实现。因此ConcreteBuilder应该有许多个,实现方法可以不同
class ConcreteBuilder1 : public Builder
{
private:
    // 一个新的构建器实例应该包含一个空白的产品对象,用于进一步的组装。
    Product1 *product;

public:
    ConcreteBuilder1()
    {
        this->Reset();
    }

    ~ConcreteBuilder1()
    {
        delete product;
    }

    void Reset()
    {
        this->product = new Product1();
    }

    // 所有生产步骤均使用同一产品实例
    void ProducePartA() const override
    {
        this->product->parts_.push_back("PartA1");
    }

    void ProducePartB() const override
    {
        this->product->parts_.push_back("PartB1");
    }

    void ProducePartC() const override
    {
        this->product->parts_.push_back("PartC1");
    }

    // 具体构建器应该提供自己的方法来检索结果。
    // 这是因为不同类型的构建器可能会创建完全不同的产品,这些产品不遵循相同的接口。
    // 因此,此类方法不能在基本构建器接口中声明(至少在静态类型编程语言中不能)

    // 通常,在将最终结果返回给客户端后,构建器实例应该准备好开始生产另一个产品。
    // 这就是为什么在 `getProduct` 方法主体末尾调用 reset 方法是一种常见做法。
    // 但是,这种行为不是强制性的,您可以让构建器等待来自客户端代码的明确 reset 调用,然后再处理之前的结果。

    // 一旦调用 GetProduct,此函数的用户就有责任释放此内存。使用智能指针来避免内存泄漏可能是一个更好的选择
    Product1 *GetProduct()
    {
        Product1 *result = this->product;
        this->Reset();
        return result;
    }
};

// Director 负责按照特定的顺序执行构建顺序,
class Director
{
private:
    Builder *builder;
    // Director 可与客户端代码传递给它的任何构建器实例配合使用。这样,客户端代码可能会改变新组装产品的最终类型。
public:
    void set_builder(Builder *builder)
    {
        this->builder = builder;
    }
    // Director 可以使用相同的构建步骤构建多个产品变体
    void BuildMinimalViableProduct()
    {
        this->builder->ProducePartA();
    }

    void BuildFullFeaturedProduct()
    {
        this->builder->ProducePartA();
        this->builder->ProducePartB();
        this->builder->ProducePartC();
    }
};

// 客户端代码创建一个构建器对象,将其传递给Director,然后启动构造过程。最终结果从构建器对象中检索。
void ClientCode(Director &director)
{
    ConcreteBuilder1 *builder = new ConcreteBuilder1();
    director.set_builder(builder);
    cout << "Standard basic product:\n";
    director.BuildMinimalViableProduct();

    Product1 *p = builder->GetProduct();
    p->ListParts();
    delete p;

    cout << "Standard full featured product:\n";
    director.BuildFullFeaturedProduct();

    p = builder->GetProduct();
    p->ListParts();
    delete p;

    // 也可以不使用Director类直接使用构造模式
    cout << "Custom product:\n";
    builder->ProducePartA();
    builder->ProducePartC();
    p = builder->GetProduct();
    p->ListParts();
    delete p;

    delete builder;
}

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

输出

Standard basic product:
Product parts: PartA1

Standard full featured product:
Product parts: PartA1, PartB1, PartC1

Custom product:
Product parts: PartA1, PartC1

相关推荐

  1. 建造模式(生成器模式)

    2024-06-13 22:58:03       36 阅读
  2. 设计模式——建造模式

    2024-06-13 22:58:03       63 阅读
  3. 设计模式-建造模式

    2024-06-13 22:58:03       55 阅读
  4. 设计模式-建造模式

    2024-06-13 22:58:03       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-13 22:58:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-13 22:58:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-13 22:58:03       82 阅读
  4. Python语言-面向对象

    2024-06-13 22:58:03       91 阅读

热门阅读

  1. SDK version 2018.3 doesnt match hw_server version 2015.2

    2024-06-13 22:58:03       23 阅读
  2. 英伟达SSD视觉算法模型训练代码解析

    2024-06-13 22:58:03       27 阅读
  3. Stable Diffusion 3 开源发布可下载体验

    2024-06-13 22:58:03       40 阅读
  4. Python PDF转化wolrd代码怎么写

    2024-06-13 22:58:03       32 阅读
  5. 【React】在 React 组件中,怎么使用useContext

    2024-06-13 22:58:03       32 阅读
  6. Cohere reranker 一致的排序器

    2024-06-13 22:58:03       37 阅读
  7. C# —— 逻辑运算符

    2024-06-13 22:58:03       33 阅读
  8. 异界传说-如何应对甲方提出的不合理需求

    2024-06-13 22:58:03       29 阅读
  9. MySQL(3)

    2024-06-13 22:58:03       29 阅读
  10. Android Unable to determine activity name

    2024-06-13 22:58:03       30 阅读