1.什么是建造者模式?
建造者模式(也被成为生成器模式),是一种创建型设计模式,软件开发过程中有的时候需要创建很复杂的对象,而建造者模式的主要思想是将对象的构建过程分为多个步骤,并为每个步骤定义一个抽象的接口。具体的构建过程由实现了这些接口的具体建造者类来完成。同时有一个指导者类负责协调建造者的工作,按照一定的顺序或逻辑来执行构建步骤,最终生成产品。
举个例子,假如我们要创建一个计算机对象,计算机由很多组件组成,例如 CPU、内存、硬盘、显卡等。每个组件可能有不同的型号、配置和制造,这个时候计算机就可以被视为一个复杂对象,构建过程相对复杂,而我们使用建造者模式将计算机的构建过程封装在一个具体的建造者类中,而指导者类则负责指导构建的步骤和顺序。每个具体的建造者类可以负责构建不同型号或配置的计算机,客户端代码可以通过选择不同的建造者来创建不同类型的计算机,这样就可以根据需要构建不同表示的复杂对象,更加灵活。
2.建造者模式的基本结构
- 产品
Product
:被构建的复杂对象, 包含多个组成部分。 - 抽象建造者
Builder
: 定义构建产品各个部分的抽象接口和一个返回复杂产品的方法getResult
- 具体建造者
Concrete Builder
:实现抽象建造者接口,构建产品的各个组成部分,并提供一个方法返回最终的产品。 - 指导者
Director
:调用具体建造者的方法,按照一定的顺序或逻辑来构建产品。
在客户端中,通过指导者来构建产品,而并不和具体建造者进行直接的交互。
3.建造者模式的大致流程
- 定义产品类:产品类应该包含多个组成部分,这些部分的属性和方法构成了产品的接口。
- 定义抽象建造者接口:创建一个接口,包含构建产品各个部分的抽象方法。这些方法通常用于设置产品的各个属性。
- 创建具体建造者:实现抽象建造者接口,构建具体的产品。
- 定义
Director
类: 指导者类来控制构建产品的顺序和步骤。 - 客户端使用建造者模式:在客户端中创建【具体建造者对象】和【指导者对象】,通过指导者来构建产品。
4.建造者模式的使用场景
使用建造者模式有下面几处优点:
-
使用建造者模式可以将一个复杂对象的构建与其表示分离,通过将构建复杂对象的过程抽象出来,可以使客户端代码与具体的构建过程解耦
-
同样的构建过程可以创建不同的表示,可以有多个具体的建造者(相互独立),可以更加灵活地创建不同组合的对象。
建造者模式适用于复杂对象的创建,当对象构建过程相对复杂时可以考虑使用建造者模式,但是当产品的构建过程发生变化时,可能需要同时修改指导类和建造者类,这就使得重构变得相对困难(缺点)。
5.C++实现建造者模式
【设计模式专题之建造者模式】4. 自行车加工 (kamacoder.com)https://kamacoder.com/problempage.php?pid=1084
题目描述:
小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。
山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。
现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。
输入描述:
输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。
接下来的 N 行,每行输入一个字符串,字符串表示客户的自行车需求。
字符串可以包含关键词 "mountain" 或 "road",表示客户需要山地自行车或公路自行车。例如:
3
mountain
road
mountain
输出描述:
对于每笔订单,输出该订单定制的自行车配置。例如:
Aluminum Frame Knobby Tires
Carbon Frame Slim Tires
Aluminum Frame Knobby Tires
在本例中:产品为自行车,所以可以有两个具体建造者:山地车建造者和公路车建造者。
按照本文所述的建造者模式的大致流程,写出C++代码如下:
#include<iostream>
#include<string>
using namespace std;
//按照建造者模式的流程来实现
//1、定义产品类,要包含产品的属性和设置方法
class Bike{
//友元函数加左移运算符重载,用来链式输出自定义数据类型的内容。
//通常类内只做友元函数的声明,具体实现要写在类外
friend ostream& operator<<(ostream & out, const Bike & bike);
private:
//自行车的属性有车架frame和车轮tires
string frame;
string tires;
public:
//定义接口方法,为属性设置具体的形式
void setFrame(const string& frame){
this->frame = frame;
}
void setTires(const string& tires){
this->tires = tires;
}
};
//
ostream& operator<<(ostream & out, const Bike & bike)
{
out<<bike.frame<<" "<<bike.tires;
return out;
}
//2.定义抽象建造者接口:创建一个接口,包含构建产品各个部分的抽象方法
class AbstractBikeBuilder{
public:
//定义构建自行车的抽象接口
virtual void bulidFrame() = 0;
virtual void buildTires() = 0;
virtual Bike& getResult() = 0;
};
//3.定义具体建造者
//3.1 定义具体山地车建造者
class MountainBikeBuilder : public AbstractBikeBuilder{
private:
Bike bike;
public:
void bulidFrame() override {
bike.setFrame("Aluminum Frame");
}
void buildTires() override{
bike.setTires("Knobby Tires");
}
Bike& getResult() override{
return bike;
}
};
//3.2 定义具体公路车建造者
class RoadBikeBuilder : public AbstractBikeBuilder{
private:
Bike bike;
public:
void bulidFrame() override {
bike.setFrame("Carbon Frame");
}
void buildTires() override{
bike.setTires("Slim Tires");
}
Bike& getResult() override{
return bike;
}
};
//4.定义指导者类来控制构建产品的顺序和步骤
class BikeDirector{
public:
//需要通过指导者类来调用建造者
Bike& construct(AbstractBikeBuilder &builder){
builder.bulidFrame();
builder.buildTires();
return builder.getResult();
}
};
int main()
{
int N;
cin>>N;
for(int i=0; i < N; i++)
{
string bikeType;
cin>>bikeType;
AbstractBikeBuilder *builder;
//根据输入,创建不同的具体建造者
if(bikeType == "mountain"){
builder = new MountainBikeBuilder();
}
else if(bikeType == "road"){
builder = new RoadBikeBuilder();
}
//指导者通过具体建造者来指导产品生产
BikeDirector director;
//接口传入具体的建造者指针,该函数内部通过建造者指针调用生产过程
Bike bike = director.construct(*builder);
//《《运算符的重载实现了自定义数据的输出
cout<<bike<<endl;
delete builder;
}
return 0;
}