什麼是設計模式,先來看段度娘的話:
設計模式(design pattern)是一套被反複使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人了解、保證代碼可靠性。 毫無疑問,設計模式于己于他人于系統都是多赢的;設計模式使代碼編制真正工程化;設計模式是軟體工程的基石脈絡,如同大廈的結構一樣。
其實我們不需要這麼專業,在我的了解,設計模式就是一種規範化的程式設計習慣,養成了這樣的思想與習慣,對我們的代碼,總是有好處了。
首先,工廠設計模式是建立對象的一種設計模式,一個嚴格意義上的工廠設計模式應該是一個純虛的構造方法。由子類進行具體對象的建立,我們可以這樣了解:現在有一個珲少牌制造工廠,這個工廠可以制造多種交通工具,我大膽一些,假設它可以制造飛機,輪船。小汽車,公共汽車,出租出和自行車,那麼,這些不同的車種雖然功能和大類别統一,但是他們的個體差異也是天地之别,就比如我飛機一小時可以飛5000公裡,自行車拼死了勁也不一定能騎20公裡。是以,如果珲少這個大工廠要生産他們,也不可能把他們放在一起生産。一個比較明智的決定是,開立分廠,比如珲少飛機工廠專門生産飛機,珲少自行車工廠專門生産自行車。
好了,如果将我們這種人類世界的思維運用于程式世界,那麼我們可以通過工廠的這種思維方式來将一些大類抽象為工廠,通過定義接口或者說是定義虛函數來規範這個大工廠的生産規模和流程,由其子類來具體實作這些方法,也就是由一個個小的分廠來明确的生産我們需要的東西。這就是工廠設計模式的基本思路。
許多開發者或許并不在意設計模式這個東西,我們可能會想,我實作我的功能就可以了,你管我怎麼設計呢。在這篇部落格的開頭就說到,在我了解中,設計模式就是一種程式設計習慣和規範,更是一種衆多開發者摸索出來的經驗,這就像農業上的套種間種和你随便種,哪一種效率高,收成好,不言而喻。那麼在軟體設計中,工廠模式的應用在哪呢?
我們先來體驗一下在ios開發中,一些使用工廠設計模式的系統類為我們帶來的便捷之處:
在ios的foundation架構中,類簇是一種常用的設計模式,他将一些相近的,私有的,具體的子類組合在一個實體的抽象類下面,我稱這個抽象類為實體的,是因為和我們互動的接口承載者,就是這個抽象大類。我們平時常用的三大類,nsstring,nsarray,nsdictionary都是類簇,我們通過他們建立的對象都是其子類對象的執行個體化,并不是他本身的執行個體化,我們還通過上面的例子來了解,我買了一輛珲少小汽車,這兩汽車的生産實際是在珲少汽車工廠生産的,但是我個人會依然認為,這是珲少工廠出産的汽車。我們可以通過列印類名來驗證:
<a href="http://my.oschina.net/u/2340880/blog/508212#">?</a>
1
2
<code>nsstring * str = [[nsstring alloc]initwithcstring:</code><code>"2"</code> <code>encoding:0];</code>
<code> </code><code>nslog(@</code><code>"%@"</code><code>,[str </code><code>class</code><code>]);</code>
結果如下:
可以看到,真實的對象是nsstring的子類__nscfstring進行執行個體化的。
如果你通過nsstring的事例還是無法體會到類簇,也就是工廠設計模式的優勢,那麼下面這個例子你一定經常遇到:nsnumber。我們在建立數字對象的時候,通常會這樣考慮,如果是int值,我需要一個intnumber的類,float值,我需要一個floatnumber類,如果foundation架構真這麼設計的話,那麼你現在就痛苦了,你不僅要記住好多這樣相似的類,調用方法時也要相應的對象調其内的方法,這使開發者的開發變得更加繁瑣,并且對于開發者來說,我并不需要知道具體我建立了什麼類,我隻是想讓他完成既定的方法。說的更通俗一點,還是上面的制造工廠,使用者并不在乎具體這個交通工具是哪個地方生産出來的,隻要它價錢和速度都是使用者預期的結果就好了。
通過上面的分析,我們大緻可以總結出工廠這種設計模式的應用場景:
(1)當一個類并不知道要建立的具體對象是什麼,交由子類處理
(2)當一些類有相似的行為和結構,隻是具體實作不同時,可以抽象出工廠
(3)使用者并不在乎具體類型,隻在乎接口約定的行為,并且這種行為有個體差異
同樣是上面的例子,我們來用代碼模拟一下:
首先,我們建立一個抽象的工程類,在其中建立一些私有的子類:
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
<code>#import <foundation/foundation.h></code>
<code>//交通工具的枚舉</code>
<code>typedef</code> <code>enum</code> <code>{</code>
<code>car,</code>
<code>boat,</code>
<code>airport,</code>
<code>bycicle,</code>
<code>bus,</code>
<code>taxi</code>
<code>}toolsname;</code>
<code>//代理</code>
<code>@protocol transportationdelegate <nsobject></code>
<code>-(</code><code>void</code><code>)tohome:(class)</code><code>class</code><code>;</code>
<code>@end</code>
<code>//抽象工廠類</code>
<code>@interface tramsportationfactory : nsobject</code>
<code>+(tramsportationfactory*)buytool:(toolsname)tool;</code>
<code>//共有的方法接口</code>
<code>-(</code><code>int</code><code>)shouldpaymoney;</code>
<code>-(</code><code>void</code><code>)run;</code>
<code>@property(nonatomic,strong)id<transportationdelegate>delegate;</code>
<code>//具體實作的子類</code>
<code>@interface carfactory : tramsportationfactory</code>
<code>@interface boatfactory : tramsportationfactory</code>
<code>@interface airportfactory : tramsportationfactory</code>
<code>@interface byciclefactory : tramsportationfactory</code>
<code>@interface taxifactory : tramsportationfactory</code>
<code>@interface busfactory : tramsportationfactory</code>
實作檔案如下:
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
<code>#import "tramsportationfactory.h"</code>
<code>@implementation tramsportationfactory</code>
<code>//實作的建立方法</code>
<code>+(tramsportationfactory*)buytool:(toolsname)tool{</code>
<code> </code><code>switch</code> <code>(tool) {</code>
<code> </code><code>case</code> <code>car:</code>
<code> </code><code>return</code> <code>[[carfactory alloc]init];</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>case</code> <code>airport:</code>
<code> </code><code>return</code> <code>[[airportfactory alloc]init];</code>
<code> </code><code>case</code> <code>bycicle:</code>
<code> </code><code>return</code> <code>[[byciclefactory alloc]init];</code>
<code> </code><code>case</code> <code>boat:</code>
<code> </code><code>return</code> <code>[[boatfactory alloc]init];</code>
<code> </code><code>case</code> <code>taxi:</code>
<code> </code><code>return</code> <code>[[taxifactory alloc]init];</code>
<code> </code><code>case</code> <code>bus:</code>
<code> </code><code>return</code> <code>[[busfactory alloc]init];</code>
<code> </code><code>default</code><code>:</code>
<code> </code><code>}</code>
<code>}</code>
<code>-(</code><code>int</code><code>)shouldpaymoney{</code>
<code> </code><code>return</code> <code>0;</code>
<code>-(</code><code>void</code><code>)run{</code>
<code> </code><code>[self.delegate tohome:[self </code><code>class</code><code>]];</code>
<code>//各自類實作具體的行為</code>
<code>@implementation carfactory</code>
<code> </code><code>return</code> <code>50;</code>
<code> </code><code>[super run];</code>
<code> </code><code>nslog(@</code><code>"car to home"</code><code>);</code>
<code>@implementation airportfactory</code>
<code> </code><code>return</code> <code>1000;</code>
<code> </code><code>nslog(@</code><code>"fly to home"</code><code>);</code>
<code>@implementation boatfactory</code>
<code> </code><code>return</code> <code>300;</code>
<code> </code><code>nslog(@</code><code>"boat to home"</code><code>);</code>
<code>@implementation busfactory</code>
<code> </code><code>return</code> <code>10;</code>
<code> </code><code>nslog(@</code><code>"bus to home"</code><code>);</code>
<code>@implementation byciclefactory</code>
<code> </code><code>nslog(@</code><code>"run to home"</code><code>);</code>
<code>@implementation taxifactory</code>
<code> </code><code>return</code> <code>100;</code>
<code> </code><code>nslog(@</code><code>"go to home"</code><code>);</code>
這樣,我們的一個生産工廠就完成了,在外面,我們隻需要知道一個類,我們的抽象父類,就可以實作個子類的行為,示例如下:
<code>- (</code><code>void</code><code>)viewdidload {</code>
<code> </code><code>[super viewdidload];</code>
<code> </code><code>tramsportationfactory * tool = [tramsportationfactory buytool:car];</code>
<code> </code><code>tool.delegate=self;</code>
<code> </code><code>[tool run];</code>
<code> </code><code>nslog(@</code><code>"花了:%d錢"</code><code>,[tool shouldpaymoney]);</code>
<code> </code><code>tramsportationfactory * tool2 = [tramsportationfactory buytool:airport];</code>
<code> </code><code>tool2.delegate=self;</code>
<code> </code><code>[tool2 run];</code>
<code> </code><code>nslog(@</code><code>"花了:%d錢"</code><code>,[tool2 shouldpaymoney]);</code>
<code> </code>
<code>-(</code><code>void</code><code>)tohome:(class)</code><code>class</code><code>{</code>
<code> </code><code>nslog(@</code><code>"%@"</code><code>,nsstringfromclass(</code><code>class</code><code>));</code>
可以看到,對于開發者,我們并不知曉carfactory類的存在,我們隻需要通過tramsportationfactory類,就能夠操作各種交通工具,達到我們的需求。