詳解C++設(shè)計(jì)模式編程中建造者模式的實(shí)現(xiàn)
建造者模式:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。這是建造者模式的標(biāo)準(zhǔn)表達(dá),不過(guò)看著讓人迷惑,什么叫構(gòu)建和表示的分離?一個(gè)對(duì)象使用構(gòu)造函數(shù)構(gòu)造之后不就固定了,只有通過(guò)它方法來(lái)改變它的屬性嗎?而且還要同樣的構(gòu)建過(guò)程搞出不同的表示,怎么可能呢?多寫(xiě)幾個(gè)構(gòu)造函數(shù)?
其實(shí)多寫(xiě)幾個(gè)構(gòu)造函數(shù),根據(jù)不同參數(shù)設(shè)置對(duì)象不同的屬性,也可以達(dá)到這樣的效果,只是這樣就非常麻煩了,每次要增加一種表示就要添加一個(gè)構(gòu)造函數(shù),將來(lái)構(gòu)造函數(shù)會(huì)多得連自己都不記得了,這違背了開(kāi)放-封閉的原則。
要不就只能設(shè)計(jì)幾個(gè)set函數(shù),每次屬性不一樣了,我就構(gòu)造一個(gè)對(duì)象,然后用set函數(shù)改變對(duì)象的屬性。這樣也可以達(dá)到效果。只是代碼就會(huì)非常冗余了,每個(gè)要用到這個(gè)對(duì)象的地方,都要寫(xiě)上好幾句語(yǔ)句,一旦對(duì)象有點(diǎn)什么變化,還得到處都改一遍,這樣就很容易出錯(cuò),以后別人看著這種神邏輯和神代碼估計(jì)也會(huì)崩潰了。而且這也違背了依賴(lài)倒轉(zhuǎn)的原則。
于是大神們就開(kāi)始想了,不能加很多構(gòu)造函數(shù),也不能直接用一堆set函數(shù),然后發(fā)現(xiàn),有些對(duì)象的構(gòu)建是固定的幾個(gè)步驟的,就像一條流水線(xiàn)一樣,任何的產(chǎn)品都是通過(guò)每一個(gè)固定的步驟拼湊出來(lái)的。例如說(shuō)一部手機(jī),先放主板,再放屏幕,再放電池,再放外殼,貼個(gè)膜就能賣(mài)幾千了,每次推出新產(chǎn)品,就換個(gè)更好的主板,換個(gè)大點(diǎn)的屏幕,再整個(gè)大容量電池,貼個(gè)超牛的高透膜,又能賣(mài)出個(gè)新價(jià)錢(qián)。就是說(shuō),這些步驟都沒(méi)有變,變的只是每個(gè)部分的東西。
這就是大神的厲害之處了,透過(guò)現(xiàn)象看本質(zhì),基本有變的,有不變的,那敢情好,面向?qū)ο蟮囊粋€(gè)重要指導(dǎo)思想就是,封裝隔離變化的,留出不變的。于是他們就用一個(gè)Builder類(lèi)把步驟中的每個(gè)部分封裝起來(lái),這個(gè)類(lèi)的主要作用就是生產(chǎn)每個(gè)部件,再抽象一下提升高度,這樣就依賴(lài)倒轉(zhuǎn)了,這樣每次只需要添加一個(gè)類(lèi),這個(gè)類(lèi)還是這幾個(gè)部分,只是內(nèi)部的實(shí)現(xiàn)已經(jīng)不一樣了,這樣就滿(mǎn)足了開(kāi)放-封閉的原則了。但還是有一個(gè)問(wèn)題,光有Builder類(lèi)還不行,雖然產(chǎn)品的每個(gè)部分都有對(duì)應(yīng)的函數(shù),但是用起來(lái)的話(huà),還是跟前面說(shuō)的set函數(shù)一樣,一用就要使用一大堆函數(shù),也就是這變的東西是封裝起來(lái)了,但這不變的東西還沒(méi)留出來(lái)。這時(shí),就添加一個(gè)Director類(lèi),這個(gè)類(lèi)就是專(zhuān)門(mén)規(guī)定組裝產(chǎn)品的步驟的,這樣只要告訴Director使用哪個(gè)Builder,就能生產(chǎn)出不同的產(chǎn)品,對(duì)于客戶(hù)端來(lái)說(shuō),只看到用了Director的一個(gè)construct函數(shù),甚是方便。
再反過(guò)來(lái)看建造者模式的定義,構(gòu)建指的就是生產(chǎn)一個(gè)產(chǎn)品的步驟,表示就是每個(gè)產(chǎn)品部分的具體實(shí)現(xiàn),通過(guò)Director封裝步驟,通過(guò)Builder封裝產(chǎn)品部分的實(shí)現(xiàn),再把他兩隔離開(kāi),就能隔離變的,留出不變的供客戶(hù)端使用。

圖中可以看到,Product是必須要知道,沒(méi)有抽象,但是這個(gè)產(chǎn)品卻可以由不同的部分組合而成。Director里的construct也是固定,沒(méi)有抽象出來(lái),如果要更改步驟,也要添加一個(gè)函數(shù),或者再添一個(gè)Diector,所以建造者模式一般應(yīng)用于步驟不會(huì)發(fā)生大的變化,而產(chǎn)品會(huì)發(fā)生大變化的情況。
常用的場(chǎng)景
C#中的StringBuilder就是一個(gè)建造者的例子,但只是一個(gè)建造者,還缺一個(gè)Director,不能算一個(gè)完整的建造者模式。建造者模式一般應(yīng)用于構(gòu)建產(chǎn)品的步驟(也可以稱(chēng)為算法)不變,而每個(gè)步驟的具體實(shí)現(xiàn)又劇烈變化的情況。
優(yōu)點(diǎn)
1.隔離了構(gòu)建的步驟和具體的實(shí)現(xiàn),為產(chǎn)品的具體實(shí)現(xiàn)提供了靈活度。
2.封裝和抽象了每個(gè)步驟的實(shí)現(xiàn),實(shí)現(xiàn)了依賴(lài)倒轉(zhuǎn)原則。
3.封裝了具體的步驟,減少了代碼的冗余。
缺點(diǎn)
1.要求構(gòu)建產(chǎn)品的步驟(算法)是不能劇烈變化的,最好是不變的,這樣就影響了靈活度。
實(shí)例
#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
//抽象類(lèi),用來(lái)安排創(chuàng)建人的具體流程,其他類(lèi)必須遵循這個(gè)流程,但是可以自己具體實(shí)現(xiàn)
class CPersonBuilder
{
public:
virtual void BuildHead()=0;
virtual void BuildBody()=0;
virtual void BuildArmLeft()=0;
virtual void BuildArmRight()=0;
virtual void BuildLegLeft()=0;
virtual void BuildLegRight()=0;
};
//創(chuàng)建瘦子的類(lèi)
class CThinPersonBuilder:public CPersonBuilder
{
public:
CThinPersonBuilder()
{
cout<<"is creating thin person "<<endl<<endl;
}
~CThinPersonBuilder()
{
cout<<"is finished for thin person"<<endl<<endl;
}
public:
void BuildHead()
{
cout<<"BuildHead"<<endl;
}
void BuildBody()
{
cout<<"BuildBody(thin)"<<endl;
}
void BuildArmLeft()
{
cout<<"BuildArmLeft"<<endl;
}
void BuildArmRight()
{
cout<<"BuildArmRight"<<endl;
}
void BuildLegLeft()
{
cout<<"BuildLegLeft"<<endl;
}
void BuildLegRight()
{
cout<<"BuildLegRight"<<endl;
}
};
//創(chuàng)建胖子的類(lèi)
class CFatPersonBuilder:public CPersonBuilder
{
public:
CFatPersonBuilder()
{
cout<<"is creating fat person"<<endl;
}
~CFatPersonBuilder()
{
cout<<"is finished for fat person"<<endl;
}
public:
void BuildHead()
{
cout<<"BuildHead"<<endl;
}
void BuildBody()
{
cout<<"BuildBody(Fat)"<<endl;
}
void BuildArmLeft()
{
cout<<"BuildArmLeft"<<endl;
}
void BuildArmRight()
{
cout<<"BuildArmRight"<<endl;
}
void BuildLegLeft()
{
cout<<"BuildLegLeft"<<endl;
}
void BuildLegRight()
{
cout<<"BuildLegRight"<<endl;
}
};
//指揮者類(lèi),用來(lái)指揮創(chuàng)建的人是瘦子還是胖子
class CPersonDirector
{
public:
CPersonDirector(CPersonBuilder *p)
{
this->m_p=p;
}
const void CreatePerson(void) const
{
m_p->BuildHead();
m_p->BuildBody();
m_p->BuildArmLeft();
m_p->BuildArmRight();
m_p->BuildLegLeft();
m_p->BuildLegRight();
}
private:
CPersonBuilder *m_p;
};
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"---------建造者模式測(cè)試案例------------------------"<<endl<<endl;
CThinPersonBuilder *p_tp=new CThinPersonBuilder();
CPersonDirector *p_dtp=new CPersonDirector(p_tp);
p_dtp->CreatePerson();
delete p_tp;
delete p_dtp;
p_tp=NULL;
p_dtp=NULL;
cout<<endl<<endl;
CFatPersonBuilder *p_fp=new CFatPersonBuilder();
CPersonDirector *p_dfp=new CPersonDirector(p_fp);
p_dfp->CreatePerson();
delete p_fp;
delete p_dfp;
p_fp=NULL;
p_dfp=NULL;
system("pause");
return 0;
}

相關(guān)文章
C語(yǔ)言中結(jié)構(gòu)體struct編寫(xiě)的一些要點(diǎn)解析
這篇文章主要介紹了C語(yǔ)言中結(jié)構(gòu)體struct編寫(xiě)的一些要點(diǎn)解析,談到了結(jié)構(gòu)體的聲明和指針指向等重要知識(shí)點(diǎn),需要的朋友可以參考下2016-04-04
C語(yǔ)言完美實(shí)現(xiàn)動(dòng)態(tài)數(shù)組代碼分享
本文給大家分享的是一則使用C語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的代碼,完美解決內(nèi)存溢出以及內(nèi)存回收問(wèn)題,有需要的小伙伴可以參考下。2016-02-02
c++中冒號(hào)(:)和雙冒號(hào)(::)的使用說(shuō)明
以下是對(duì)c++中冒號(hào)和雙冒號(hào)的用法進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下2013-07-07
OpenCV獲取鼠標(biāo)左鍵點(diǎn)擊位置圖像的像素值
這篇文章主要為大家詳細(xì)介紹了OpenCV獲取鼠標(biāo)左鍵點(diǎn)擊位置圖像的像素值,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
C語(yǔ)言用遞歸函數(shù)實(shí)現(xiàn)漢諾塔
大家好,本篇文章主要講的是C語(yǔ)言用遞歸函數(shù)實(shí)現(xiàn)漢諾塔,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-01-01
漫談C++哈夫曼樹(shù)的原理及實(shí)現(xiàn)
給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹(shù),若該樹(shù)的帶權(quán)路徑長(zhǎng)度達(dá)到最小,稱(chēng)這樣的二叉樹(shù)為最優(yōu)二叉樹(shù),也稱(chēng)為哈夫曼樹(shù)(Huffman?Tree)。本文將通過(guò)圖片為大家詳細(xì)講講C++哈夫曼樹(shù)的原理及實(shí)現(xiàn),需要的可以參考一下2022-08-08

