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

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

注:参考视频:【设计模式(完整版)】https://www.bilibili.com/video/BV1Zd4y1t7HK?p=3&vd_source=eee55dc084ebc7a8d4f5db673a3c06f9

分类:(对象)创建型

问题:

1.构造一个房屋,需要考虑是否有车库,游泳池,花园,雕塑等,需要对诸多成员变量进行初始化工作.都写在构造函数里?每种都可能创建一个新的类?

写在构造函数里有一大堆参数.但是我可能建这个房屋不需要游泳池,但是建另一个房屋需要.写在构造函数里有的参数不需要而且过于杂乱.

每种都创建一个新的类,那样我们的类就会很多,也不合适.

注:生成器这个设计模式构造的东西是比较复杂的对象,如果我们构造的对象比较简单也并不需要生成器.

2.相同的步骤需要能够产生不同的产品,例如使用木头和玻璃盖出来的是普通住房.用黄金和水晶建造出来的是宫殿.

1.生成器(Builder):声明通用的产品构造步骤

2.具体生成器(Concrete Builders):提供构造过程的不同实现.具体生成器也可以构造不遵循通用接口的产品

3.产品(Products):最终生成的对象.由不同生成器构造的产品无需属于同一类层次结构或接口

4.主管(Director):定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置

5.客户端(Client):必须将某个生成器对象与主管类关联.一般情况下,只需通过主管类构造函数的参数进行一次性关联即可

你是一个Client,你觉得自己盖房子不专业,所以请了一个Director.(程序中并不一定需需要Director类,Client代码可以直接以特定顺序调用创建步骤.不过,Director类中非常适合放入各种例行构造流程,以便在程序中反复使用)

这里按照类图讲.

如果你(Client)对Director说要盖一个简单的房子,那么Director类只需要调用buildStepA就好了,如果不是简单的房子,就走buliderStepB和builderStepZ.Director依赖Builder这个接口,通过Builder去完成相应的建房子步骤.请了设计师,但是没有施工队啊,所以你(Client)就会去找施工队ConcreteBuilder(依赖ConcreteBuilder).其中ConcreteBuilder1可能生成一个房子,但是ConcreteBuilder2可能直接你一个房子的说明书.

注意,不同于其他创造模式,不同的ConcreteBuilder可以生产不相关的产品.Product1和Product2可以不遵循相同的接口.因此在C++这样的静态类型语言中,getResult方法不能放到Builder接口里(因为ConcreteBuilder1和ConcreteBuilder2可能调用的接口完全不同,返回的类型完全不同,所以C++不可能当做一个统一的函数去放到基类给继承).

本身我们构造的东西比较复杂,所以我们给他分步骤,这样我就很灵活,让Directior去根据哪些步骤去生成,在Director中有某些固定的步骤,而不同的步骤我可以根据不同的施工队来产生不同的东西.

例如:我可以盖一个房子和画一个房屋结构图,我可以用相同的流程,但是我调用的接口和基类不同,所以我们生成的产品完全不同.

reset()函数

生产一个产品,你需要先new一个出来空的对象,在填充内容之前这个对象要存在(把内存准备好)

每调用一个buildStep(),我们就给他加一点特性(增加一个车库等)

getResult()函数返回配置好new出来的product

另外,builder.reset()不一定要放在Director的make(type)里,也可以放到getResult()中调用.

这样我们的Client类就可以写得很简单了:

我们首先先找一个Director,但是Director需要一个施工队(ConcreteBuilder1)配合他,所以找一个施工队(ConcreteBuilder1)介绍给Director.然后Director发出指令,ConcreteBuilder1产生具体的产品,所以调用ConcreteBuilder1的getResult接受产品.

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

完整代码:

注:代码中的产品2和ConcreteBuilder2为笔者另加的,以图让读者方便理解类图.另外为了方便理解代码,笔者并未在Client中调用ConcreteBuilder2和产出产品2(Client里写了写发现结果太乱了所以删了).

#include <iostream>
#include <vector>
#include <string>
//产品1
class SimpleHouse
{
public:
    //如果不使用生成器,那么我们就在这里的构造函数加参数或者设计新的类,但是参数或类一多就麻烦
    std::vector<std::string> m_parts;
    void printParts() const
    {
        std::cout << "SimpleHouse 包括:" << std::endl;
        for (int i = 0; i < m_parts.size(); ++i)
        {
            std::cout << m_parts[i] << std::endl;
        }
        std::cout << "----------------------------------" << std::endl;
    }
};
//产品2
class SimpleHouseUseInstructionBook
{
public:
    void printUseInstructionBook() const
    {
        std::cout << "这是一个简单房子说明书" << std::endl;
    }
};
//接口,Director和ConcreteBuilder都要依赖这个(依赖倒置)
class Builder
{
public:
    virtual ~Builder(){}
    virtual void reset() = 0;
    virtual void makeBaseHouse() = 0;
    virtual void makeGarage() = 0;
    virtual void makePool() = 0;
    virtual void makeUseInstructionBook() = 0;
};
//ConcreteBuilder1
class SimpleHouseBuilder:public Builder
{
private:
    SimpleHouse* m_simplehouse;
public:
    SimpleHouseBuilder()
    {
        reset();
    }
    ~SimpleHouseBuilder()
    {
        delete m_simplehouse;
    }
    virtual 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");
    }
    virtual void makeUseInstructionBook() override
    {
        //ConcreteBuilder2的功能,这里不实现
    }
    SimpleHouse* getResult()
    {
        //不直接返回m_simplehouse的原因是要移交控制权
        //返回result指针时,谁调用getResult,谁就要维护result指针,负责回收result指针指向的内存
        //而这个类中的指针调用reset()调用新的对象了,不维护已经产生的这个对象了
        SimpleHouse* result = m_simplehouse; 
        reset();
        return result;
    }
};
//ConcreteBuilder2
class SimpleHouseUseInstructionBookBuilder:public Builder
{
private:
    SimpleHouseUseInstructionBook* m_UseInstructionBook;
public:
    SimpleHouseUseInstructionBookBuilder()
    {
        reset();
    }
    ~SimpleHouseUseInstructionBookBuilder()
    {
        delete m_UseInstructionBook;
    }
    virtual void makeUseInstructionBook() override 
    {
        std::cout << "你好" << std::endl;
    }
    virtual void reset() override
    {
        m_UseInstructionBook = new SimpleHouseUseInstructionBook();
    }
    SimpleHouseUseInstructionBook* getResult()
    {
        SimpleHouseUseInstructionBook* result = m_UseInstructionBook;
        reset();
        return result;
    }
};
​
//封装为Director类
class Director
{
private:
    Builder* m_builder;
public:
    void setBuiler(Builder* builder)
    {
        m_builder = builder;
    }
    //使用Director类的好处,可以分类
    void makeBaseHouse()
    {
        m_builder->makeBaseHouse();
    }
    void makeSimpleHouse()
    {
        m_builder->makeBaseHouse();
        m_builder->makeGarage();
    }
    void makeFullHouse()
    {
        m_builder->makeBaseHouse();
        m_builder->makeGarage();
        m_builder->makePool();
    }
    void makeUseInstructionBook()
    {
        m_builder->makeUseInstructionBook();
    }
};
//Client
void client(Director* director = NULL)
{
    //不封装Director类时的做法
    std::cout << "客户自己设计流程:----------------------------" << std::endl;
    SimpleHouseBuilder* builder = new SimpleHouseBuilder();
    builder->makeBaseHouse();
    builder->makeGarage();
    SimpleHouse* simpleHouse = builder->getResult();
    simpleHouse->printParts();
    delete simpleHouse;
    //上面这个simpleHouse和下面这个simpleHouse是两个房子
    //具体见getResult
    //封装Director类
    std::cout << "主管负责设计流程:----------------------------" << std::endl;
    director->setBuiler(builder);
    director->makeFullHouse();
    simpleHouse = builder->getResult();
    simpleHouse->printParts();
    delete simpleHouse;
    delete builder;
}
int main()
{
    Director director;
    client(&director);
}

  • 42
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值