一.簡介
建造者模式也是六個建立型設計模式之一,用于對象的建立過程。建造者模式的主要作用是将對象的建構和表示分離,使得同樣的建構過程可以建立不同的具體對象。在建立一系列對象時,對象的建立過程大體相同,但是具體過程不同時,就可以使用建立者模式。比如我門畫一個人的時候,都是需要畫頭,身體,胳膊和腿的,但是具體怎麼畫就大不相同了。建造者模式給出了一個創造時的模闆,并且給出了建立對象的實際接口(或者是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方法。
最後附上一篇大牛的部落格連結: http://blog.csdn.net/lovelion/article/details/7426855