一.简介
建造者模式也是六个创建型设计模式之一,用于对象的创建过程。建造者模式的主要作用是将对象的构建和表示分离,使得同样的构建过程可以创建不同的具体对象。在创建一系列对象时,对象的创建过程大体相同,但是具体过程不同时,就可以使用创建者模式。比如我门画一个人的时候,都是需要画头,身体,胳膊和腿的,但是具体怎么画就大不相同了。建造者模式给出了一个创造时的模板,并且给出了创建对象的实际接口(或者是Director类)。我们要改变创建过程的时候,只需要覆写相关的具体创建过程函数,就可以改变创建的过程。
建造者模式的UML图如下:
二.建造者模式的具体实现
上个例子,例子中写的比较清楚:
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
string m_partA;
string m_partB;
string m_partC;
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual void BuildPartC() = 0;
void SetPartA(string a){m_partA = a;}
void SetPartB(string b){m_partB = b;}
void SetPartC(string c){m_partC = c;}
void Show()
{
cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
}
Builder* GetResult()
{
return this;
}
};
//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
void BuildPartA() override;
void BuildPartB() override;
void BuildPartC() override;
};
void ConcreteBuilder::BuildPartA()
{
SetPartA("Con1 partA");
}
void ConcreteBuilder::BuildPartB()
{
SetPartB("Con1 partB");
}
void ConcreteBuilder::BuildPartC()
{
SetPartC("Con1 partC");
}
//创建director,提供创建接口
class BuilderDirector
{
public:
void Build(Builder* buider)
{
buider->BuildPartA();
buider->BuildPartB();
buider->BuildPartC();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
//创建一个具体的Builder
Builder* builder = new ConcreteBuilder();
//创建builderdirector
BuilderDirector* builderdir = new BuilderDirector();
//通过builderdirector来控制创建
builderdir->Build(builder);
//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
Builder* result = builder->GetResult();
result->Show();
system("pause");
return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .
请按任意键继续. . .
创建对象的时候,初始化操作并不应该放在构造函数中(可能有一些默认初值,比如指针置空的操作),真正的初始化应该是一个单独的Init操作。但是这个Init操作有时也是很复杂的,需要初始化各个子模块。如果对象的创建过程大致类似,仅仅是各个子模块的初始化有所差异,那么就将子模块的初始化放在派生类中进行具体的修改。创建的过程遵循一系列固定的流程,这就是建造者模式。
例子中,Builder基类仅仅给出了三个子模块创建的抽象接口,ConcreteBuilder继承了Builder,实现了具体创建的过程。通过Director类固定好的创建模式,多态调用具体的ConcreteBuilder实现了对象的创建。
三.建造者模式的使用条件
建造者模式主要是对于构建一个包含多个组件的对象,使用相同的构建过程构建不同种类的对象的一种设计模式。
在以下场景中适用建造者模式:
(1)对象由多个不同的组件构成。
(2) 对象的各个组件可能有相互依赖,可能还需要指定构建顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
适用建造者模式,我们可以不必了解对象内部细节,将对象的创建过程和对象本身解耦,让相同的创建过程可以创建不同的对象。并且,如果我们新增了一种对象,只需要给出具体的ConcreteBuilder即可,复合“开放封闭原则”。将创建过程分成各个部分,而不是单独的一个Init,可以让创建过程更加清晰。
但是使用建造者模式也限制了一些条件,要创建的对象必须有相同的结构,都覆写基类的具体创建过程,并且使用相同的创建顺序。
四.创建过程中的控制
上面说过,创建过程中有些限制条件,但是,如果我们想要更加灵活的进行创建,让某些创建过程工作,某些创建过程不工作的话,就可以通过一种叫做“钩子函数”的东东,进行控制。
看一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
string m_partA;
string m_partB;
string m_partC;
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual void BuildPartC() = 0;
void SetPartA(string a){m_partA = a;}
void SetPartB(string b){m_partB = b;}
void SetPartC(string c){m_partC = c;}
//钩子函数,默认是返回true的,如果想控制其为false,只需要在派生类将其覆写即可
virtual bool IsNeedPartA(){return true;}
void Show()
{
cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
}
Builder* GetResult()
{
return this;
}
};
//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
void BuildPartA() override;
void BuildPartB() override;
void BuildPartC() override;
};
void ConcreteBuilder::BuildPartA()
{
SetPartA("Con1 partA");
}
void ConcreteBuilder::BuildPartB()
{
SetPartB("Con1 partB");
}
void ConcreteBuilder::BuildPartC()
{
SetPartC("Con1 partC");
}
//创建director,提供创建接口
class BuilderDirector
{
public:
void Build(Builder* buider)
{
//此处使用函数进行判断,是否需要初始化partA
if(buider->IsNeedPartA())
{
buider->BuildPartA();
}
buider->BuildPartB();
buider->BuildPartC();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
//创建一个具体的Builder
Builder* builder = new ConcreteBuilder();
//创建builderdirector
BuilderDirector* builderdir = new BuilderDirector();
//通过builderdirector来控制创建
builderdir->Build(builder);
//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
Builder* result = builder->GetResult();
result->Show();
system("pause");
return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .
请按任意键继续. . .
默认情况钩子函数返回的是true,如果我们想要不初始化A部分,那么就在Concrete类中将钩子函数覆写,返回false,这样,BuilderDirector中就会在判断的时候,去除PartA的创建。
我们在ConCreteBuilder中覆写IsNeedPartA函数:
<span style="white-space:pre"> </span>bool IsNeedPartA() override
{
return false;
}
结果:
Con1 partB Con1 partC
请按任意键继续. . .
请按任意键继续. . .
可见PratA在钩子函数为false的情况下没有被构建。
五.简化版本的建造者模式
类似工厂模式那样,创建对象可以使用一个static方法而省略具体的工厂。建造者模式也可以将Director省略,直接将创建过程放在Builder类中。
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
string m_partA;
string m_partB;
string m_partC;
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual void BuildPartC() = 0;
void SetPartA(string a){m_partA = a;}
void SetPartB(string b){m_partB = b;}
void SetPartC(string c){m_partC = c;}
void Show()
{
cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
}
Builder* GetResult()
{
return this;
}
//将Director的内容合并到抽象类中
static void CreateBuilder(Builder* builder);
};
void Builder::CreateBuilder(Builder* builder)
{
builder->BuildPartA();
builder->BuildPartB();
builder->BuildPartC();
}
//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
void BuildPartA() override;
void BuildPartB() override;
void BuildPartC() override;
};
void ConcreteBuilder::BuildPartA()
{
SetPartA("Con1 partA");
}
void ConcreteBuilder::BuildPartB()
{
SetPartB("Con1 partB");
}
void ConcreteBuilder::BuildPartC()
{
SetPartC("Con1 partC");
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建一个具体的Builder
Builder* builder = new ConcreteBuilder();
//通过Builder自带的static方法,构建builder
Builder::CreateBuilder(builder);
//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
Builder* result = builder->GetResult();
result->Show();
system("pause");
return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .
请按任意键继续. . .
这里,由于Builder通常为抽象类,不能直接实例化,所以采用的是将具体Builer的指针作为参数传递给CreateBuilder方法,在该方法中调用一系列初始化的函数完成对象的创建。该方法不需要对象对应就可以使用,故采用了static方法。
最后附上一篇大牛的博客链接: