建造者模式:將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。這是建造者模式的標(biāo)準(zhǔn)表達,不過看著讓人迷惑,什么叫構(gòu)建和表示的分離?一個對象使用構(gòu)造函數(shù)構(gòu)造之后不就固定了,只有通過它方法來改變它的屬性嗎?而且還要同樣的構(gòu)建過程搞出不同的表示,怎么可能呢?多寫幾個構(gòu)造函數(shù)?
其實多寫幾個構(gòu)造函數(shù),根據(jù)不同參數(shù)設(shè)置對象不同的屬性,也可以達到這樣的效果,只是這樣就非常麻煩了,每次要增加一種表示就要添加一個構(gòu)造函數(shù),將來構(gòu)造函數(shù)會多得連自己都不記得了,這違背了開放-封閉的原則。
要不就只能設(shè)計幾個set函數(shù),每次屬性不一樣了,我就構(gòu)造一個對象,然后用set函數(shù)改變對象的屬性。這樣也可以達到效果。只是代碼就會非常冗余了,每個要用到這個對象的地方,都要寫上好幾句語句,一旦對象有點什么變化,還得到處都改一遍,這樣就很容易出錯,以后別人看著這種神邏輯和神代碼估計也會崩潰了。而且這也違背了依賴倒轉(zhuǎn)的原則。
于是大神們就開始想了,不能加很多構(gòu)造函數(shù),也不能直接用一堆set函數(shù),然后發(fā)現(xiàn),有些對象的構(gòu)建是固定的幾個步驟的,就像一條流水線一樣,任何的產(chǎn)品都是通過每一個固定的步驟拼湊出來的。例如說一部手機,先放主板,再放屏幕,再放電池,再放外殼,貼個膜就能賣幾千了,每次推出新產(chǎn)品,就換個更好的主板,換個大點的屏幕,再整個大容量電池,貼個超牛B的高透膜,又能賣出個新價錢。就是說,這些步驟都沒有變,變的只是每個部分的東西。
這就是大神的厲害之處了,透過現(xiàn)象看本質(zhì),基本有變的,有不變的,那敢情好,面向?qū)ο蟮囊粋€重要指導(dǎo)思想就是,封裝隔離變化的,留出不變的。于是他們就用一個Builder類把步驟中的每個部分封裝起來,這個類的主要作用就是生產(chǎn)每個部件,再抽象一下提升高度,這樣就依賴倒轉(zhuǎn)了,這樣每次只需要添加一個類,這個類還是這幾個部分,只是內(nèi)部的實現(xiàn)已經(jīng)不一樣了,這樣就滿足了開放-封閉的原則了。但還是有一個問題,光有Builder類還不行,雖然產(chǎn)品的每個部分都有對應(yīng)的函數(shù),但是用起來的話,還是跟前面說的set函數(shù)一樣,一用就要使用一大堆函數(shù),也就是這變的東西是封裝起來了,但這不變的東西還沒留出來。這時,就添加一個Director類,這個類就是專門規(guī)定組裝產(chǎn)品的步驟的,這樣只要告訴Director使用哪個Builder,就能生產(chǎn)出不同的產(chǎn)品,對于客戶端來說,只看到用了Director的一個construct函數(shù),甚是方便。
再反過來看建造者模式的定義,構(gòu)建指的就是生產(chǎn)一個產(chǎn)品的步驟,表示就是每個產(chǎn)品部分的具體實現(xiàn),通過Director封裝步驟,通過Builder封裝產(chǎn)品部分的實現(xiàn),再把他兩隔離開,就能隔離變的,留出不變的供客戶端使用。
圖中可以看到,Product是必須要知道,沒有抽象,但是這個產(chǎn)品卻可以由不同的部分組合而成。Director里的construct也是固定,沒有抽象出來,如果要更改步驟,也要添加一個函數(shù),或者再添一個Diector,所以建造者模式一般應(yīng)用于步驟不會發(fā)生大的變化,而產(chǎn)品會發(fā)生大變化的情況。
常用的場景
C#中的StringBuilder就是一個建造者的例子,但只是一個建造者,還缺一個Director,不能算一個完整的建造者模式。建造者模式一般應(yīng)用于構(gòu)建產(chǎn)品的步驟(也可以稱為算法)不變,而每個步驟的具體實現(xiàn)又劇烈變化的情況。
優(yōu)點
1.隔離了構(gòu)建的步驟和具體的實現(xiàn),為產(chǎn)品的具體實現(xiàn)提供了靈活度。
2.封裝和抽象了每個步驟的實現(xiàn),實現(xiàn)了依賴倒轉(zhuǎn)原則。
3.封裝了具體的步驟,減少了代碼的冗余。
缺點
1.要求構(gòu)建產(chǎn)品的步驟(算法)是不能劇烈變化的,最好是不變的,這樣就影響了靈活度。
實例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include "stdafx.h" #include <stdlib.h> #include <iostream> using namespace std; //抽象類,用來安排創(chuàng)建人的具體流程,其他類必須遵循這個流程,但是可以自己具體實現(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)建瘦子的類 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)建胖子的類 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; } }; //指揮者類,用來指揮創(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<< "---------建造者模式測試案例------------------------" <<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; } |