我所理解的設計模式(C++實現)——建造者模式(Builder Pattern)

LCL_data發表於2013-04-04

解決的問題:

我建立的這個物件比較複雜,且該物件裡面的成員函式用不同的實現來表示不同的例項,換句話說就是同樣的物件構建過程可以有不同的表示。比如我那天去吃過橋米線,他們有不同的套餐,套餐裡包含的種類是一樣的,都有一碗米線,一份冷盤,一杯飲料。但是不同的套餐裡這3樣又都不是全部一樣的。此時我們就可以用建造者模式。


類圖結構:


1.建造者(Builder)角色:給出一個抽象介面,以規範產品物件的各個組成成分的建造。一般而言,此介面獨立於應用程式的商業邏輯。模式中直接建立產品物件的是具體建造者(Concrete Builder)角色。具體建造者類必須實現這個介面所要求的方法:一個是建造方法,另一個是結果返還方法。此時就是米線店的員工,按照收銀員的要求的去準備具體的套餐,放入適當的米線,冷盤和飲料。

2.具體建造者(Concrete Builder)角色:擔任這個角色的是於應用程式緊密相關的類,它們在應用程式呼叫下建立產品例項。這個角色主要完成的任務包括:實現Builder角色提供的介面,一步一步完成建立產品例項的過程。在建造過程完成後,提供產品的例項。是具體的做某個套餐的員工。

3.指導者(Director)角色:擔任這個角色的類呼叫具體建造者角色以建立產品物件。導演者並沒有產品類的具體知識,真正擁有產品類的具體知識的是具體建造者物件。是收銀員,他知道我想要什麼套餐,他會告訴裡面的米線店員工去準備什麼套餐。

4.產品(Product)角色:產品便是建造中的複雜物件。指導者角色是於客戶端打交道的角色。導演者角色將客戶端建立產品的請求劃分為對各個零件的建造請求,再將這些請求委派給具體建造者角色。具體建造者角色是做具體建造工作的,但卻不為客戶端所知。就是最後的套餐,所有東西放到一起端過來。


樣例實現:

// CplusplusBuild.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <vector>
#include <string>
#include <iostream>
using namespace std;
//product
class Food
{
private:
	vector<string> mFoodName;
	vector<int> mFoodPrice;

public:
	void add(string foodName,int price)
	{
		mFoodName.push_back(foodName);		
		mFoodPrice.push_back(price);
	}

	void show()
	{
		cout<<"Food List" <<endl;
		cout<<"-------------------"<<endl;
		for(int i=0;i<mFoodName.size();i++)
		{
			cout<<mFoodName[i]<<" "<<mFoodPrice[i]<<endl;
		}
	}
};

//builder
class Builder
{
public:
	virtual void BuildRiceNoodles() {};
	virtual void BuildCoolDish(){};
	virtual void BuildDrink(){};
	virtual Food * getFood(){return NULL;}
};


//builderA
class BuilderA:public Builder
{
private:
	Food *food;

public:
	BuilderA(){food = new Food();}
	void BuildRiceNoodles()
	{
		food->add("RiceNoodlesA",20);
	}
	void BuildCoolDish()
	{
		food->add("CoolDishA",20);
	}
	void BuildDrink()
	{
		food->add("DrinkA",20);
	}
	Food * getFood()
	{
		return food;
	}
};

//builderB
class BuilderB:public Builder
{
private:
	Food *food;
public:
	BuilderB(){food = new Food();}
	void BuildRiceNoodles()
	{
		food->add("RiceNoodlesB",10);
	}
	void BuildCoolDish()
	{
		food->add("CoolDishB",10);
	}
	void BuildDrink()
	{
		food->add("DrinkB",10);
	}
	Food * getFood()
	{
		return food;
	}
};

//director
class FoodManager
{
public:
	void Construct(Builder * builder)
	{
		builder->BuildRiceNoodles();
		builder->BuildDrink();
		builder->BuildCoolDish();
	}
};

//clent
int _tmain(int argc, _TCHAR* argv[])
{
	FoodManager *foodManager= new FoodManager();

	Builder * builder = new Builder();

	// the following code can use simple factory;
	char ch;
	cout<<"input your food Type (A or B):";
	cin>>ch;
	if(ch=='A')
	{
		builder = new BuilderA();
	}else if(ch=='B')
	{
		builder = new BuilderB();
	}

	foodManager->Construct(builder);
	Food * food = builder->getFood();
	food->show();
	return 0;
}


建造者模式的擴充套件:

  建造者模式在使用過程中可以演化出多種形式:

     省略抽象建造者角色

     如果系統中只需要一個具體的建造者的話,可以省略掉抽象建造者。這是程式碼可能如下:

 

//director
class FoodManager
{
private:
	BuilderA * builder;
public:
	FoodManager() {builder = new BuilderA();};
	void Construct()
	{
		builder->BuildRiceNoodles();
		builder->BuildDrink();
		builder->BuildCoolDish();
	}
};

      省略指導者角色

      在具體建造者只有一個的情況下,如果抽象建造者角色已經被省略掉,那麼還可以省略掉指導者角色,讓Builder自己扮演指導者和建造者雙重角色。這是程式碼可能如下:

//builder
class Builder
{
private:
	Food * food;
public:
	 Builder(){food = new Food();}
	 void BuildRiceNoodles() {//..};
	 void BuildCoolDish(){//..};
	 void BuildDrink(){//..};
	 Food * getFood(){return food;}
	 void Construct()
	 {
		 BuildRiceNoodles();
		 BuildCoolDish();
		 BuildDrink();
	 }
};

同時,客戶端也需要進行相應的調整,如下:

//client
int _tmain(int argc, _TCHAR* argv[])
{
	Builder * builder = new Builder();
    builder->Construct();
	Food *food = builder->getFood();
	food->show();
	return 0;
}

    C#中的StringBuilder就是這樣一個例子。


實現要點:

1.建造者模式主要用於“分步驟構建一個複雜的物件”,在這其中“每個步驟”是一個穩定的演算法,而複雜物件的各個步驟之間則經常變化。

2.上一篇所說的抽象工廠模式解決“系列物件”的需求變化,而建造者模式解決單個物件裡“物件部分”的需求變化。

產品不需要抽象類,特別是由於建立物件的演算法複雜而導致使用此模式的情況下或者此模式應用於產品的生成過程,其最終結果可能差異很大,不大可能提煉出一個抽象產品類。

3.建立者中的建立子部件的介面方法不是抽象方法而是空方法,不進行任何操作,具體的建立者只需要覆蓋需要的方法就可以,但是這也不是絕對的,特別是類似文字轉換這種情況下,預設的方法將輸入原封不動的輸出是合理的預設操作。


適用性:

以下情況應當使用建造者模式:

1、需要生成的產品物件有複雜的內部結構。
2、需要生成的產品物件的屬性相互依賴,建造者模式可以強迫生成順序。
3、 在物件建立過程中會使用到系統中的一些其它物件,這些物件在產品物件的建立過程中不易得到。


效果

1、建造者模式的使用使得產品的內部表象可以獨立的變化。使用建造者模式可以使客戶端不必知道產品內部組成的細節。
2、每一個Builder都相對獨立,而與其它的Builder無關。
3、可使對構造過程更加精細控制。

4、將構建程式碼和實現程式碼分開。

5、建造者模式的缺點在於難於應付“分步驟構建演算法”的需求變動。


LCL_data原創於CSDN.NET【http://blog.csdn.net/lcl_data/article/details/8758477


相關文章