设计模式C++生成器(建造者模式)
注:参考视频:【设计模式(完整版)】https://www.bilibili.com/video/BV1Zd4y1t7HK?p=3&vd_source=eee55dc084ebc7a8d4f5db673a3c06f9
分类:(对象)创建型
问题:
1.构造一个房屋,需要考虑是否有车库,游泳池,花园,雕塑等,需要对诸多成员变量进行初始化工作.都写在构造函数里?每种都可能创建一个新的类?
写在构造函数里有一大堆参数.但是我可能建这个房屋不需要游泳池,但是建另一个房屋需要.写在构造函数里有的参数不需要而且过于杂乱.
每种都创建一个新的类,那样我们的类就会很多,也不合适.
注:生成器这个设计模式构造的东西是比较复杂的对象,如果我们构造的对象比较简单也并不需要生成器.
2.相同的步骤需要能够产生不同的产品,例如使用木头和玻璃盖出来的是普通住房.用黄金和水晶建造出来的是宫殿.![](https://i-blog.csdnimg.cn/blog_migrate/d9c372c66545b143f773274994d33208.png)
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);
}