建造者模式及C++實現


下面是我自己對建造者模式的理解。具體我還沒在開發中應用過,這只是對於書本的理解。

建造者模式

建造者模式:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。這是建造者模式的標准表達,不過看着讓人迷惑,什么叫構建和表示的分離?一個對象使用構造函數構造之后不就固定了,只有通過它方法來改變它的屬性嗎?而且還要同樣的構建過程搞出不同的表示,怎么可能呢?多寫幾個構造函數?

其實多寫幾個構造函數,根據不同參數設置對象不同的屬性,也可以達到這樣的效果,只是這樣就非常麻煩了,每次要增加一種表示就要添加一個構造函數,將來構造函數會多得連自己都不記得了,這違背了開放-封閉的原則。

要不就只能設計幾個set函數,每次屬性不一樣了,我就構造一個對象,然后用set函數改變對象的屬性。這樣也可以達到效果。只是代碼就會非常冗余了,每個要用到這個對象的地方,都要寫上好幾句語句,一旦對象有點什么變化,還得到處都改一遍,這樣就很容易出錯,以后別人看着這種神邏輯和神代碼估計也會崩潰了。而且這也違背了依賴倒轉的原則。

於是大神們就開始想了,不能加很多構造函數,也不能直接用一堆set函數,然后發現,有些對象的構建是固定的幾個步驟的,就像一條流水線一樣,任何的產品都是通過每一個固定的步驟拼湊出來的。例如說一部手機,先放主板,再放屏幕,再放電池,再放外殼,貼個膜就能賣幾千了,每次推出新產品,就換個更好的主板,換個大點的屏幕,再整個大容量電池,貼個超牛B的高透膜,又能賣出個新價錢。就是說,這些步驟都沒有變,變的只是每個部分的東西。

這就是大神的厲害之處了,透過現象看本質,基本有變的,有不變的,那敢情好,面向對象的一個重要指導思想就是,封裝隔離變化的,留出不變的。於是他們就用一個Builder類把步驟中的每個部分封裝起來,這個類的主要作用就是生產每個部件,再抽象一下提升高度,這樣就依賴倒轉了,這樣每次只需要添加一個類,這個類還是這幾個部分,只是內部的實現已經不一樣了,這樣就滿足了開放-封閉的原則了。但還是有一個問題,光有Builder類還不行,雖然產品的每個部分都有對應的函數,但是用起來的話,還是跟前面說的set函數一樣,一用就要使用一大堆函數,也就是這變的東西是封裝起來了,但這不變的東西還沒留出來。這時,就添加一個Director類,這個類就是專門規定組裝產品的步驟的,這樣只要告訴Director使用哪個Builder,就能生產出不同的產品,對於客戶端來說,只看到用了Director的一個construct函數,甚是方便。

再反過來看建造者模式的定義,構建指的就是生產一個產品的步驟,表示就是每個產品部分的具體實現,通過Director封裝步驟,通過Builder封裝產品部分的實現,再把他兩隔離開,就能隔離變的,留出不變的供客戶端使用。

image

圖中可以看到,Product是必須要知道,沒有抽象,但是這個產品卻可以由不同的部分組合而成。Director里的construct也是固定,沒有抽象出來,如果要更改步驟,也要添加一個函數,或者再添一個Diector,所以建造者模式一般應用於步驟不會發生大的變化,而產品會發生大變化的情況。

 

常用的場景

C#中的StringBuilder就是一個建造者的例子,但只是一個建造者,還缺一個Director,不能算一個完整的建造者模式。建造者模式一般應用於構建產品的步驟(也可以稱為算法)不變,而每個步驟的具體實現又劇烈變化的情況。

 

優點

1.隔離了構建的步驟和具體的實現,為產品的具體實現提供了靈活度。

2.封裝和抽象了每個步驟的實現,實現了依賴倒轉原則。

3.封裝了具體的步驟,減少了代碼的冗余。

 

缺點

1.要求構建產品的步驟(算法)是不能劇烈變化的,最好是不變的,這樣就影響了靈活度。

 

C++實現代碼

Builder.h

#ifndef _BUILDER_H_
#define _BUILDER_H_

#include <stdio.h>

class Product{
public:
	Product();
	~Product();

	void setPartA(int param);
	void setPartB(int param);
	void setPartC(int param);

	void show();

private:
	int partA;
	int partB;
	int partC;

};


class AbstractBuilder{
public:
	AbstractBuilder();
	virtual ~AbstractBuilder();

	virtual void createProduct() = 0;
	virtual void buildPartA(int param) = 0;
	virtual void buildPartB(int param) = 0;
	virtual void buildPartC(int param) = 0;

	virtual Product* getProduct() = 0;
};


class Builder: public AbstractBuilder{
public:
	Builder();
	~Builder();

	void createProduct();
	void buildPartA(int param);
	void buildPartB(int param);
	void buildPartC(int param);

	Product* getProduct();

private:
	Product* curProduct;

};

#endif

 

Builder.cpp

#include "Builder.h"



Product::Product()
{

}


Product::~Product()
{

}


void Product::setPartA(int param)
{
	partA = param;
}


void Product::setPartB(int param)
{
	partB = param;
}


void Product::setPartC(int param)
{
	partC = param;
}


void Product::show()
{
	fprintf(stderr,"partA = %d  partB = %d  partC = %d\n",partA,partB,partC);
}


AbstractBuilder::AbstractBuilder()
{

}


AbstractBuilder::~AbstractBuilder()
{

}


Builder::Builder()
:curProduct(NULL)
{

}


Builder::~Builder()
{

}


void Builder::createProduct()
{
	fprintf(stderr,"創建一個產品空殼\n");
	curProduct = new Product();
}


void Builder::buildPartA(int param)
{
	fprintf(stderr,"正在構建產品的A部分\n");
	curProduct->setPartA(param);
}


void Builder::buildPartB(int param)
{
	fprintf(stderr,"正在構建產品的B部分\n");
	curProduct->setPartB(param);
}


void Builder::buildPartC(int param)
{
	fprintf(stderr,"正在構建產品的C部分\n");
	curProduct->setPartC(param);
}


Product* Builder::getProduct()
{
	//我的理解就是產品交出去之后,怎么釋放怎么弄就不歸建造者管了
	return curProduct;
}

 

Director.h

#ifndef _DIRECTOR_H_
#define _DIRECTOR_H_

#include "Builder.h"

class Director
{
public:
	Director(AbstractBuilder* builder);
	~Director();

	void construct();

private:
	AbstractBuilder* curBuilder;
};

#endif

 

Director.cpp


#include "Director.h"


Director::Director(AbstractBuilder* builder)
{
	curBuilder = builder;
}


Director::~Director()
{

}


void Director::construct()
{
	if (!curBuilder)
		return;

	curBuilder->createProduct();
	curBuilder->buildPartA(1);
	curBuilder->buildPartB(2);
	curBuilder->buildPartC(3);
}
client.cpp

#include "Director.h"



int main()
{
	AbstractBuilder* builder = new Builder();
	Director* director = new Director(builder);

	director->construct();
	
	Product* product = builder->getProduct();
	product->show();
	return 0;
}

 

g++ -o client client.cpp Builder.cpp Director.cpp

 

運行結果

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM