3 生成器(Builder)模式

生成器模式

1.1 分类

(对象)创建型

1.2 提出问题

  1. 构造一个房屋,需要考虑是否有车库,游泳池,花园,雕塑等,需要对诸多成员变量进行初始化工作。都写在构造函数里?每种可能都创建一个新的类?
  2. 相同的步骤需要能够产生不同的产品,例如使用木头和玻璃盖出来的是普通住房。用黄金和水晶建造出来的是宫殿。

1.3 解决方案

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。即将对象构造代码从产品类中抽取出来,并将其放在一个名为Builder的独立对象中。

1.4 实现类图

  1. 生成器(Builder):声明通用的产品构造步骤。
  2. 具体生成器(Concrete Builders):提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。
  3. 产品(Products):最终生成的对象。由不同生成器构造的产品无需属于同一类层次结构或接口。
  4. 主管(Director):定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置。
  5. 客户端(Client):必须将某个生成器对象与主管类关联。一 般情况下,只需通过主管类构造函数的参数进行一次性关联即可。

:程序中并不一定需要主管类。客户端代码可直接以特定顺序调用创建步骤。不过,主管类中非常适合放入各种例行构造流程,以便在程序中反复使用。
:不同于其他创造模式,不同的ConcreteBuilder可以生产不相关的产品。Product1和Product2可以不遵循相同的接口。因此在C++这样的静态类型语言中,getResult方法不能放到Builder接口里。

1.5 示例代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
//产品1
class SimpleHouse {
public:
    std::vector<std::string> m_parts;
    void printParts() const {
        std::cout << "SimpleHouse 包括:\n";
        for (int i = 0; i < m_parts.size(); ++i) {
            std::cout << m_parts[i] << std::endl;
        }
        std::cout << "----------------------\n";
    }
};
//生成器
class Builder {
public:
    virtual ~Builder() {}
    virtual void reset() = 0;
    virtual void makeBaseHouse() = 0;
    virtual void makeGarage() = 0;
    virtual void makePool() = 0;
};
//concreteBuilder1,施工队
class SimpleHouseBuilder : public Builder {
private:
    SimpleHouse* m_simplehouse;
public:
    SimpleHouseBuilder() {
        reset();
    }
    ~SimpleHouseBuilder() { delete m_simplehouse; }
    void reset() override{
        m_simplehouse = new SimpleHouse();
    }
    virtual void makeBaseHouse() override{
        m_simplehouse->m_parts.push_back("BaseHouse");
    }
    virtual void makeGarage() override {
        m_simplehouse->m_parts.push_back("Garage");
    }
    virtual void makePool() override {
        m_simplehouse->m_parts.push_back("Pool");
    }

    SimpleHouse* getResult() {
        SimpleHouse* result = m_simplehouse;
        reset();
        return result;
    }
};
//主管:负责流程
class Director {
private:
    Builder* m_builder;
public:
    void setBuilder(Builder* builder) {
        m_builder = builder;
    }
    void makeSimpleHouse() {
        m_builder->makeBaseHouse();
        m_builder->makeGarage();
    }
    void makeFullFuncHouse() {
        m_builder->makeBaseHouse();
        m_builder->makeGarage();
        m_builder->makePool();
    }
};
//客户端(也可以封装成类)
void client(Director* director) {
    std::cout << "客户自己设计流程:---------------------\n";
    SimpleHouseBuilder* builder = new SimpleHouseBuilder();
    builder->makeBaseHouse();
    builder->makeGarage();
    SimpleHouse * simpleHouse= builder->getResult();
    simpleHouse->printParts();
    delete simpleHouse;
    std::cout << "主管负责设计流程:---------------------\n";
    director->setBuilder(builder);
    director->makeFullFuncHouse();
    simpleHouse = builder->getResult();
    simpleHouse->printParts();
    delete simpleHouse;
    delete builder;
}
int main()
{
    Director director;
    client(&director);
}

1.6 举个栗子

下面关于生成器模式的例子,演示了如何复用相同的对象构造代码来生成不同类型的产品:例如汽车(Car)和其相应的使用手册(Manual)。

1.7 总结

  1. 将对象的构造过程分解到若干个步骤,这就使程序可以更加精细,有效地控制整个对象的构造。
  2. 生成不同形式的产品时,可以复用相同的制造代码。
  3. 单一职责原则。可以将复杂构造代码从产品的业务逻辑中分离出来。
  4. 当增加新的具体生成器时,不必修改主管的代码,满足开闭原则。
  5. 缺点 :如果产品之间的差异性很大,则不适合使用建造者模式,使用范围受到一定的限制。
相关推荐
-To be number.wan2 小时前
C++ 赋值运算符重载:深拷贝 vs 浅拷贝的生死线!
前端·c++
XXYBMOOO3 小时前
内核驱动开发与用户级驱动开发:深度对比与应用场景解析
linux·c++·驱动开发·嵌入式硬件·fpga开发·硬件工程
范纹杉想快点毕业6 小时前
返璞归真还是拥抱现代?——嵌入式研发中的“裸机开发”与RTOS全景解析
c语言·数据库·mongodb·设计模式·nosql
SoveTingღ7 小时前
【问题解析】我的客户端与服务器交互无响应了?
服务器·c++·qt·tcp
温宇飞7 小时前
内存异常
c++
挖矿大亨9 小时前
C++中深拷贝与浅拷贝的原理
开发语言·c++·算法
Bruce_kaizy10 小时前
c++图论——生成树之Kruskal&Prim算法
c++·算法·图论
雾岛听蓝11 小时前
C++:模拟实现string类
开发语言·c++
XFF不秃头11 小时前
力扣刷题笔记-合并区间
c++·笔记·算法·leetcode
编程之路,妙趣横生11 小时前
STL(七) unordered_set 与 unordered_map 基本用法 + 模拟实现
c++