定義
"将一個複雜對象的建構與它的表現分離,使得同樣的建構過程可以建立不同的表現"。
- 最初的定義出現于《設計模式》(Addison-Wesley,1994)。
看這個概念,可能感覺很是抽象,能看懂但是不知道有什麼用。我們打一個比方來了解上面的定義。打比方之前,咱們先來聊聊這個設計模式是幹什麼用的?我們為什麼要用這個模式呢?建造者模式負責将建構複雜對象的過程和它的部件解耦,也就是過程和部件的解耦。比如說汽車,是一個很複雜的對象,它有很多的部件,車輪、發動機、座椅、車門、油箱等等;它的組裝過程也很複雜(需要專業人士按步驟進行裝配),建造者模式就是為了将部件群組裝過程分開的。同樣的,我們使用的計算機也一樣,有很多的部件,組裝過程也很複雜(當然,對于我們這樣的專業人士可能感覺不複雜)。建造者模式最大的好處就是使得建構過程和表現分離,是以若需要改變一個産品的表現,隻需要重新定義一個具體的建造者就可以了(這句話了解起來有點難度,還是拿車來打比方,我們将車的組裝過程獨立出來,用這個組裝過程,我們即可以組裝寶馬車,也可以組裝奔馳車,或者其他的車型,我們隻需要重新定義一個具體的建造者(用于産品表現的類)就可以了)。
動機
在軟體系統中,有時候會遇到一個複雜對象(比如說上面例子中的汽車)的建立,它通常由幾個部分的子對象采用一定的算法(過程)構成;由于需求的變化,這個複雜對象的各個部分經常面臨着劇烈的變化(比如上面例子中,各種車型用的車門、方向盤、發動機等,是不一樣的),但是将各個部分組合在一起的算法(過程)是相對穩定的。
建造者模式就是在這樣的需求下誕生的,它封裝了變化點(組成部分),使得同樣的建構過程可以建立不同的表現。
結構圖
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL3E2MmFGN4ATMxMjN2YjZ5IDZzQjZkdjM5YGOlJGMjBTLxADOxIjMwEzLcJTMzEDMy8CX5QzNwQzLcd2bsJ2Lc12bj5ycn9Gbi52YuAzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
從結構圖可以看到,生成器模式有兩個重要的角色:Director(指導者)和Builder(建造者)。Director知道Builder應該建造什麼(建造的過程),Builder知道如何建造(表現)。在Director類中定義了一個construct方法,指導具體的建造者ConcreteBuilder的對象去buildPart。Builder是一個抽象接口(協定),該協定中包含建造各個部分的方法(buildPart),用來建構實際的産品Product,另外還有一個getResult方法,用來向用戶端傳回建構完成的Product。
這樣說不知道大家是不是感覺很抽象?那咱們用一個生活的例子來通俗點說。比如現在我要在老家修一個房子,首先我不知道怎麼修房子(砌牆,缺建造者),然後我也不知道怎麼設計(修幾個房間,房間的布局,房間的窗戶怎麼設計等等,缺指導者),于是我找來一幫民工(建造者),他們會砌牆;另外我還得找設計師(指導者),他知道怎麼設計;最後,我還要確定民工(建造者)聽設計師(指導者)的指導,哪裡需要砌一堵牆,哪裡需要安裝窗戶等等,這樣民工(建造者)就開始蓋房子,在這個建造過程中,設計師(指導者)隻負責設計和下達指令。房子建成功後,民工(建造者)向我交房。說白了,就是Director(指導者)負責把控宏觀方面(過程),Builder(建造者)負責把控微觀方面(表現) 。
下面咱們還是通過代碼來說明這個結構圖。
建造者模式的代碼
Product.m(部分代碼):
1 - (id)init
2
3 {
4
5 self = [superinit];
6
7
8
9 if (self)
10
11 {
12
13 arrParts = [NSMutableArrayarray];
14
15 }
16
17
18
19 returnself;
20
21 }
22
23
24
25 - (void)addPart:(NSString *)part
26
27 {
28
29 [arrPartsaddObject:part];
30
31 }
32
33
34
35 - (void)show
36
37 {
38
39 for (NSString *strPart inarrParts)
40
41 {
42
43 NSLog(@"%@",strPart);
44
45 }
46
47 }
Builder.h(部分代碼):
1 @classProduct;
2
3 @protocol Builder <NSObject>
4
5
6
7 - (void)addPartOne;
8
9 - (void)addPartTwo;
10
11 - (Product *)getResult;
12
13
14
15 @end
ConcreteBuilder.m(部分代碼):
1 - (id)init
2
3 {
4
5 self = [superinit];
6
7
8
9 if (self)
10
11 {
12
13 product = [[Productalloc] init];
14
15 }
16
17
18
19 returnself;
20
21 }
22
23
24
25 - (void)addPartOne
26
27 {
28
29 [productaddPart:@"part one"];
30
31 }
32
33
34
35 - (void)addPartTwo
36
37 {
38
39 [productaddPart:@"part two"];
40
41 }
42
43
44
45 - (Product *)getResult
46
47 {
48
49 returnproduct;
50
51 }
52
53 Director.m(部分代碼):
54
55 - (void)construct:(id<Builder>)builder
56
57 {
58
59 [builder addPartOne];
60
61 [builder addPartTwo];
62
63 }
用戶端調用代碼:
1 Director *director = [[Directoralloc] init];
2
3 id<Builder> builder = [[ConcreteBuilderalloc] init];
4
5
6
7 [director construct:builder];
8
9 Product *product = [builder getResult];
10
11 [product show];
12
13
14
15 [builder release];
16
17 [director release];
何時使用建造者模式
建造者模式常用于如下情形:
- 需要建立涉及各種部件的複雜對象。建立對象的算法應該獨立于部件的裝配方式。
- 建構過程需要以不同的方式建構對象。
源碼下載下傳 傳回目錄
循自然之道,撫浮躁之心