一、定义
GOF定义:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种。Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。
例如,计算机是由 CPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。
这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异,即产品的组成部分是不变的,但每一部分是可以灵活选择的。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。
二、角色
1.建造者(Builder):
为创建一个产品对象的各个部件指定抽象接口。
2.具体建造者(ConcreteBuilder):
实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
3.指挥者(Director):
指挥并构造一个使用Builder接口的对象。
4. 产品(Product):
表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
UML类图如下:
三、实现
#include<iostream>
using namespace std;
//具体产品,房子,由门、窗、墙等组成。
class House{
private:
string m_door;
string m_window;
string m_wall;
public:
void setDoor(string door){
this->m_door = door;
}
void setWindow(string window){
this->m_window = window;
}
void setWall(string wall){
this->m_wall = wall;
}
string getDoor(){
cout<<this->m_door.c_str()<<endl;
return this->m_door;
}
string getWindow(){
cout<<this->m_window.c_str()<<endl;
return this->m_window;
}
string getWall(){
cout<<this->m_wall.c_str()<<endl;
return this->m_wall;
}
};
//Builder,提供构建房子各个组件的接口
class Builder{
public:
virtual void builderDoor() = 0;
virtual void builderWindow() = 0 ;
virtual void builderWall() = 0 ;
virtual House* getHouse() = 0 ;
};
//指挥者,调用具体建造者构造具体的产品,和用户直接交互,使用户不用具体知道产品的实现细节。
class Director{
public:
Director(){
}
void construct(Builder *builder){
builder->builderDoor();
builder->builderWindow();
builder->builderWall();
}
};
//具体建造者,对对象各部件进行设置
//建造公寓
class FlatBuilder:public Builder{
private:
House* m_house;
public:
FlatBuilder(){
this->m_house = new House;
}
void builderDoor(){
this->m_house->setDoor("flat door");
}
void builderWindow(){
this->m_house->setWindow("flat window");
}
void builderWall(){
this->m_house->setWall("flat wall");
}
House* getHouse(){
return this->m_house;
}
};
//建造别墅
class VillaBuilder:public Builder{
private:
House* m_house;
public:
VillaBuilder(){
this->m_house = new House;
}
void builderDoor(){
this->m_house->setDoor("valli door");
}
void builderWindow(){
this->m_house->setWindow("valli window");
}
void builderWall(){
this->m_house->setWall("valli wall");
}
House* getHouse(){
return this->m_house;
}
};
int main(){
House *house = nullptr;
Builder *builder = nullptr;
Director *director = nullptr;
//创建指挥者
director = new Director();
//client将建造房子的事交给指挥者,完全不用知晓怎样建造
builder = new FlatBuilder();
director->construct(builder);
//建造好,交付房子
house = builder->getHouse();
house->getDoor();
house->getWindow();
house->getWall();
delete house;
delete builder;
builder = new VillaBuilder();
director->construct(builder);
house = builder->getHouse();
house->getDoor();
house->getWindow();
house->getWall();
delete house;
delete builder;
delete director;
return 0 ;
}
四、优缺点
主要优点如下:
各个具体的建造者相互独立,有利于系统的扩展。
客户端不必知道产品内部组成的细节,便于控制细节风险。
缺点如下:
产品的组成部分必须相同,这限制了其使用范围。
如果产品的内部变化复杂,该模式会增加很多的建造者类。
五、建造者模式与工厂模式的区别
Factory模式:
1、有一个抽象的工厂。
2、实现一个具体的工厂—汽车工厂。
3、A工厂生产汽车A,得到汽车产品A。
4、B工厂生产汽车B,得到汽车产品B。
这样做,实现了购买者和生产线的隔离。强调的是结果。
Builder模式:
1、引擎工厂生产引擎产品,得到汽车部件A。
2、轮胎工厂生产轮子产品,得到汽车部件B。
3、底盘工厂生产车身产品,得到汽车部件C。
4、将这些部件放到一起,形成刚好能够组装成一辆汽车的整体。
5、将这个整体送到汽车组装工厂,得到一个汽车产品。
这样做,目的是为了实现复杂对象生产线和其部件的解耦。强调的是过程
两者的区别在于:
Factory模式不考虑对象的组装过程,而直接生成一个我想要的对象。
Builder模式先一个个的创建对象的每一个部件,再统一组装成一个对象。
Factory模式所解决的问题是,工厂生产产品。
而Builder模式所解决的问题是工厂控制产品生成器组装各个部件的过程,然后从产品生成器中得到产品。
六、应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。