天天看點

IOS設計模式淺析之工廠方法模式(Factory Method)

概述

  在軟體系統中,經常面臨着“某個對象”的建立工作,由于需求的變化,這個對象的具體實作經常面臨着劇烈的變化,但是它卻擁有比較穩定的接口。

  如何隔離出這個易變對象的變化,使得系統中“其它依賴該對象的對象”不随着需求的改變而改變,這就是本章要說的Factory Method模式了。

定義

  “定義建立對象的接口,讓子類決定執行個體化哪一個類。工廠方法使得一個類的執行個體化延遲到其子類。”

  • 最初的定義出現于《設計模式》(Addison-Wesley,1994)。

結構圖

IOS設計模式淺析之工廠方法模式(Factory Method)

  抽象産品Product(可以是接口或者抽象類)定義了工廠方法建立的對象的接口和産品的共性;ConcreteProduct實作了Product。Creator定義了傳回Product類型對象的工廠方法;ConcreteCreator實作了Creator,傳回具體的ConcreteProduct的執行個體。

  從結構圖可以看出,在工廠方法模式中,核心的工廠類(Creator)不再負責所有産品的建立,而是将具體建立工作交給子類(ConcreteCreator)去做。這個核心類僅僅負責給出具體工廠必須實作的接口,而不接觸哪一個産品類被執行個體化這種細節。與直接建立新的具體産品相比,工廠方法模式讓客戶程式可以要求由工廠方法建立的對象擁有一組共同的行為。這樣往類層次結構中引入新的具體産品時,并不需要修改用戶端代碼,因為傳回的任何具體對象的接口都跟用戶端一直在用的從前的接口相同。從結構圖也可以看到,工廠方法模式中的工廠類與産品類往往具有平行的等級結構,它們之間一一對應。

示例

  根據工廠方法模式的定義和結構圖,現在将簡單工廠模式中的示例,用工廠方法模式來實作,先看使用工廠方法模式實作的結構圖:

IOS設計模式淺析之工廠方法模式(Factory Method)

  從圖中可以看到,在簡單工廠模式中,由工廠類(ChartFactory)根據參數負責建立具體的産品(線形圖、餅狀圖);而在工廠方法模式中,工廠類(Factory)隻定義了一個建立産品的抽象接口,建立具體産品的工作由具體的工廠(線形圖工廠、餅狀圖工廠)來實作。如果需要增加其他類型的圖形繪制,那麼使用簡單工廠模式實作的話,首先需要增加一個其他圖形繪制的類,例如柱狀圖(BarChart),然後修改工廠類(ChartFactory),在裡面加分支語句來判斷;使用工廠方法模式實作的話,不僅需要增加圖形繪制類,還需要增加具體工廠類(BarFactory)。看到這裡,可能大家會感覺到,工廠方法模式不但沒有減少難度,反而增加了一些類和複雜度。這樣來看,是不是沒有必要使用工廠方法模式?咱們再回顧一下開篇介紹的六大設計原則,有一個原則是“開放-關閉原則”,簡單工廠模式不僅對擴充開放,而且對修改也開放,違反了“開放-關閉原則”。工廠方法模式是簡單工廠模式的進一步抽象,它保持了簡單工廠模式的優點(去除了用戶端與具體産品的依賴),而且克服了它的缺點(違反開放-關閉原則”)。它的缺點是每增加一個産品,就需要加一個産品工廠的類,增加了額外的開發工作量。理論分析就到這裡,接下來看看代碼:

  IChart.h:

1 @protocol IChart <NSObject>
2 
3 - (void)drawing;      

  LineChart.m(部分代碼):

1 - (void)drawing
2 
3 {
4 
5     NSLog(@"LineChart drawing.");
6 
7 }      

  PieChart.m(部分代碼):

1 - (void)drawing
2 
3 {
4 
5     NSLog(@"PieChart drawing.");
6 
7 }      

  Factory.h:

1 @protocol Factory <NSObject>
2 
3 - (id<IChart>)createChart;      

  LineFactory.m(部分代碼):

1 - (id<IChart>)createChart
2 {
3 
4     return [[[LineChartalloc] init] autorelease];
5 
6 }      

  PieFactory. .m(部分代碼):

1 - (id<IChart>)createChart
2 {
3 
4     return [[[PieChartalloc] init] autorelease];
5 
6 }      

  用戶端調用代碼:

1         id<Factory> factory = [[[LineFactoryalloc] init] autorelease];
2 
3 //        id<Factory> factory = [[[PieFactory alloc] init] autorelease];
4 
5         id<IChart> chart = [factory createChart];
6 
7         [chart drawing];      

  從調用代碼可以看出,工廠方法模式從代碼中消除了對應用程式特有類的耦合。代碼秩序處理Product抽象接口(這裡是id<IChart>),這樣同一代碼就可以複用。

思考

  從上面的用戶端調用代碼看到,如果有多處調用繪圖的地方,我們需要每處都進行修改,這樣的話,實際上也沒有達到我們的效果:應對變化,盡可能少的修改代碼。那麼該怎樣處理這種情況呢?

  下面一種方式可以做到:

1 //        id<Factory> factory = [[[LineFactory alloc] init] autorelease];
2 //        id<Factory> factory = [[[PieFactory alloc] init] autorelease];
3         id<Factory> factory = [[[NSClassFromString(@"PieFactory") alloc] init] autorelease];
4 
5         id<IChart> chart = [factory createChart];
6         [chart drawing];
7         
8         [NSNumber numberWithBool:YES];      

  這樣的話,我們可以将@"PieFactory"放到配置檔案中,當我們需要繪制線形圖的時候,隻需要修改配置檔案即可,用戶端的所有代碼都不需要改變。

何時使用工廠方法模式

  • 編譯時無法準确預期要建立的對象的類;
  • 類想讓其子類決定在運作時建立什麼;
  • 類有若幹輔助類為其子類,而你想将傳回哪個子類這一資訊局部化。

  源碼下載下傳   傳回目錄

循自然之道,撫浮躁之心