天天看點

設計模式學習筆記--建造者模式一.簡介二.建造者模式的具體實作三.建造者模式的使用條件四.建立過程中的控制五.簡化版本的建造者模式

一.簡介

建造者模式也是六個建立型設計模式之一,用于對象的建立過程。建造者模式的主要作用是将對象的建構和表示分離,使得同樣的建構過程可以建立不同的具體對象。在建立一系列對象時,對象的建立過程大體相同,但是具體過程不同時,就可以使用建立者模式。比如我門畫一個人的時候,都是需要畫頭,身體,胳膊和腿的,但是具體怎麼畫就大不相同了。建造者模式給出了一個創造時的模闆,并且給出了建立對象的實際接口(或者是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

繼續閱讀