1、定义:
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
2、使用场景:
- 产品的表示比较复杂,构建一个产品,需要暴露太多产品的属性。这时候可以通过一个建造某一种特殊类型产品的的建造者来封装。(前面是一个工厂模式。为了容易扩展,引入抽象建造者和指挥者这两个角色)
- 建造过程比较固定,建造的顺序一定;
3、结构图:
上面一幅图可以用包工头与工人、工人甲、工人乙类似的关系来描述。
包工头就是其中的Director,工人就是Builder,工人甲与工人乙就是具体的建造类ConcreteBuilder。
construct可以返回一个产品,也可以不返回,通过调用具体构建类的”GetProduct()”方法,返回子类中产品。产品句柄在ConcreteBuilder类中。
4、组成:
- 产品类:一般是一个较复杂的对象;
- 抽象建造者:统一产品构建方式,为扩展用。一般有两类抽象方法,一类方法用来建造对象,这一类的方法每一个用来建造产品的不同部分,一类方法用来返回建造的对象;
- 具体建造者:实现抽象建造者所有未实现的方法;
指挥者:有一个Construct(param)方法,该方法的参数是抽象建造者,用来接收具体的建造者对象。该方法统一了对象的建造步骤及建造顺序。
抽象建造者的用途
- 规范了产品建造的步骤(反映了产品的组成);
- 便于扩展系统;
指挥者的用途
- 隔离了客户与产品的创建过程;
- 控制产品的创建过程(或者说创建流程、创建顺序);
5、使用优点:
- 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
- 可以更加精细地控制产品的创建过程 ,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
一类产品,要有一个抽象建造者,若干个具体建造者,用来建造不同表示(组成)的该类型产品。
6、举例:
下面这个例子以肯德基为例,说明在肯德基中不同顾客点了不同的套餐的场景:
服务员(Director)创建不同的套餐(ConcreteBuilder),创建套餐可以分为创建吃的(BuildPartA),创建喝的(BuildPartB)。
顾客A点了汉堡和雪碧 –》 则具体实现类可以设计为
class ConcreteBuilder_Hanbao_Xuebi : public Builder {
pulic:
BuilderFood() { 添加汉堡; }
BuilderDrink() { 添加雪碧; }
};顾客B点了鸡肉和可乐 –》 则具体实现类可以设计为
class ConcreteBuilder_Jirou_Kele : public Builder {
pulic:
BuilderFood() { 添加鸡肉; }
BuilderDrink() { 添加可乐; }
};
总结:
一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式。
下面的BuilderPattern.cpp是具体使用建造者模式的代码,里面体现了建造者模式中几个组成对象的关系。
/*!
* \file BuilderPattern.cpp
* \date 2017/08/07 21:00
* \author common
*
* \brief 简要介绍建造者模式的使用
*/
#include <iostream>
class Wheel
{};
class Body
{};
// 抽象产品类
class Car
{
public:
virtual void BuildupWheel(const Wheel& wheel) = 0;
virtual void BuildupBody(const Body& body) = 0;
protected:
Wheel _wheel;
Body _body;
};
// 具体产品,法拉利
class Ferrari : public Car
{
public:
virtual void BuildupWheel(const Wheel& wheel) override
{
_wheel = wheel;
std::cout << "this is the way of buildup wheel of Ferrari" << std::endl;
}
virtual void BuildupBody(const Body& body) override
{
_body = body;
std::cout << "this is the way of buildup body of Ferrari" << std::endl;
}
};
// 具体产品,劳斯莱斯
class RollsRoyce : public Car
{
public:
virtual void BuildupWheel(const Wheel& wheel) override
{
_wheel = wheel;
std::cout << "this is the way of buildup wheel of RollsRoyce" << std::endl;
}
virtual void BuildupBody(const Body& body) override
{
_body = body;
std::cout << "this is the way of buildup body of RollsRoyce" << std::endl;
}
};
//////////////////////////////////////////////////////////////////////////
// 抽象构建类
class Builder
{
public:
virtual void BuildupWheel(const Wheel& wheel) = 0;
virtual void BuildupBody(const Body& body) = 0;
virtual Car* GetProduct() = 0;
};
// 具体构建类,构建法拉利
class ConcreteBuilderFerrari : public Builder
{
public:
ConcreteBuilderFerrari() { _pCar = new Ferrari(); }
virtual void BuildupWheel(const Wheel& wheel) { _pCar->BuildupWheel(wheel); }
virtual void BuildupBody(const Body& body) { _pCar->BuildupBody(body); }
virtual Car* GetProduct() { return _pCar; }
private:
Car* _pCar;
};
// 具体构建类,构建劳斯莱斯
class ConcreteBuilderRollsRoyce : public Builder
{
public:
ConcreteBuilderRollsRoyce() { _pCar = new RollsRoyce(); }
virtual void BuildupWheel(const Wheel& wheel) { _pCar->BuildupWheel(wheel); }
virtual void BuildupBody(const Body& body) { _pCar->BuildupBody(body); }
virtual Car* GetProduct() { return _pCar; }
private:
Car* _pCar;
};
//////////////////////////////////////////////////////////////////////////
// 指挥者类
class Director
{
public:
void Consturct(Builder* builder)
{
// 传入一个轮子,但是不同产品组装轮子的方式不同
builder->BuildupWheel(Wheel());
// 传入一个车身,但是不同产品组装车身的方式不同
builder->BuildupBody(Body());
}
};
int main(int argc, char* argv[])
{
Director* director = new Director;
Builder* ferrariBuilder = new ConcreteBuilderFerrari;
Builder* rollsRoyceBuilder = new ConcreteBuilderRollsRoyce;
director->Consturct(ferrariBuilder);
director->Consturct(rollsRoyceBuilder);
Ferrari* ferrari = static_cast<Ferrari*>(ferrariBuilder->GetProduct());
RollsRoyce* rollsRoyce = static_cast<RollsRoyce*>(rollsRoyceBuilder->GetProduct());
system("pause");
}