天天看點

【設計模式】抽象工廠模式 Abstract Factory Pattern

簡單工廠模式是一個工廠類根據工廠方法的參數建立不出不同的産品, 工廠方法模式是每一個産品都有一個一一對應的工廠負責建立該産品。那麼今天要講的抽象工廠模式是一個工廠能夠産生關聯的一系列産品。抽象工廠模式相對于簡單工廠和工廠方法模式來着更具抽象性。

我們先來看一個簡單的需求: 甲方要開發一套辦公自動化軟體,其中有一個非常重要的功能就是要能夠導入Word 文檔和Excel 文檔。

開發人員拿到需求後就開始編碼了,  很快代碼寫完了:

用戶端調用代碼:

輸出結果:

【設計模式】抽象工廠模式 Abstract Factory Pattern

看起來不錯, 但是看代碼,用戶端的代碼和具體的實作之間是直接new出來的 ,簡直就是面向具體程式設計,沒有接口沒有抽象,是不是違背了ISP原則了?,那好開發人員決定提出一個抽象層,提出一個抽象的文檔接口,   用簡單工廠模式來實作這個需求:

UML 圖如下:

【設計模式】抽象工廠模式 Abstract Factory Pattern

代碼如下:

用戶端調用:

輸出:

【設計模式】抽象工廠模式 Abstract Factory Pattern

看起來完美這是一個标準的靜态工廠模式的實作。

第一次需求變更: 增加 對Power Point 的導入支援

增加了一個産品相當于,因為之前應用了簡單工廠模式現在改起來很簡單。

UML 圖:

【設計模式】抽象工廠模式 Abstract Factory Pattern

代碼:

【設計模式】抽象工廠模式 Abstract Factory Pattern

沒問題,一起都在控制之中。

第二次需求變更: 支援office 2007 以後的文檔格式。

Offcie 2007是個坎,2007之前的文檔格式和2007以後的文檔格式不一 樣, word 在2007前的文檔字尾是.doc, 2007 及以後就變成.docx了這個看似簡單的需求實則是增加了小一半的工作量啊,新的格式的文檔要重新進行解碼才能拿到正确的資料,拿剛剛實作的簡單工廠設計模式來應對這次變更就要新增加3個産品類并且要工廠來建立建立者三個類的執行個體。看來靜态工廠已經不能再适應這一次的需求變化了,會導緻靜态工廠方法的邏輯變得異常複雜難以維護。那用工廠方法模式來解決這個問題,工廠方法剛好可以将産品的建立工作提取到單獨的工廠中去完成,重構下工廠将靜态工廠模式替換成工廠方法模式:

【設計模式】抽象工廠模式 Abstract Factory Pattern
【設計模式】抽象工廠模式 Abstract Factory Pattern

一個産品一個實作類,一個工廠類,這樣職責單一符合SRP,但是系統中的類在成倍的增加,有點複雜了,如果在增加一個系列的産品那還了得。

那麼能不能減少一些類呢?經過分析我們發現,這些導入的文檔中2007之前的一系列文檔的解析規則基本類似實作的技術也是類似的,2007及以後的文檔的解析規則類似。是以我們可以把這些産品分成兩個系列,2007之前的成為Document系列,2007以後的文檔成為DocumentX系列, 那麼我們就可以建立兩個具體的工廠來建立Document系列和DocumentX系列, 從另一個次元來看,Word 和WordX, Excel 和ExcelX,PowerPoint 和 PowerPointX的的關系也很密切,因為都是同一個産品,隻是處在不同的系列上,他們各自的編碼又各自類似,是以在這個次元上可以将其提出一組新的接口,IWordDocument 用于處理word的導入(Word和WordX),IExcelDocument 用處理Excel的導入(Excel 和ExcelX),IPowerPoint用于處理 PowerPoint 導入(PowerPoint和PowerPointX),根據這個思路重構代碼:

UML 圖

【設計模式】抽象工廠模式 Abstract Factory Pattern
【設計模式】抽象工廠模式 Abstract Factory Pattern

這一次工廠的數量得到了控制,這裡隻有兩個工廠類就搞定了,DocumentFactory 負責建立office 2007之前的文檔對象,DocumentXFactory 負責建立 office 2007以及以後的文檔對象。這就解決了工廠方法模式工廠類随着産品增加随之增加帶來的複雜性,以及不易維護的問題。這樣如果在增加一系列産品就變得容易了很多,隻需要再建立一個系列産品的具體工廠并繼承自抽象工廠,以及實作系列産品的抽象接口的具體類就可以了。

随着需求的變化一步一步的經過重構代碼也一步一步從簡單工廠模式到工廠方法模式再到抽象工廠模式了。現在文檔處理代碼就是一個典型的抽象工廠模式了,那麼下面來看看抽象工廠模式到底是什麼?

抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或互相依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,它是一種對象建立型模式。在抽象工廠模式中,每一個具體工廠都提供了多個工廠方法用于産生多種不同類型的産品,這些産品構成了一個産品族(産品系列).
【設計模式】抽象工廠模式 Abstract Factory Pattern

抽象工廠模式結構圖

它聲明了一組用于建立一系列産品的方法,每一個方法對應建立一種産品。

它實作了在抽象工廠中聲明的建立産品的方法,生成一組具體産品,這些産品構成了一個産品系列,每個産品都在同一個系列中。

它為每種産品聲明接口,在抽象産品中聲明了産品所具有的業務方法。

它定義具體工廠生産的具體産品對象,實作抽象産品接口中聲明的業務方法。

在抽象工廠中聲明了多個工廠方法,用于建立不同類型的産品,抽象工廠可以是接口,也可以是抽象類或者具體類,其典型代碼如下:

用戶端調用代碼:

輸出:

【設計模式】抽象工廠模式 Abstract Factory Pattern

抽象工廠模式隔離了具體類的生成,使得客戶并不需要知道什麼被建立。由于這種隔離,更換一個具體工廠就變得相對容易,所有的具體工廠都實作了抽象工廠中定義的那些公共接口,是以隻需改變具體工廠的執行個體,就可以在某種程度上改變整個軟體系統的行為。比如常用的配置+反射就可輕松替換掉工廠進而替換掉整個以為邏輯。

當一個産品族中的多個對象被設計成一起工作時,它能夠保證用戶端始終隻使用同一個産品系列中的對象。

增加新的産品系列很友善,無須修改已有系統,隻需要增加具體産品類和具體工廠就可以了符合“開閉原則(OCP)“。

增加新的産品麻煩,需要對原有系統進行較大的修改,甚至需要修改抽象層代碼,這顯然會帶來較大的不便,違背了“開閉原則(OCP)“。如果新增一個産品就要在抽象工廠中增加一個建立該産品的方法。這樣就牽一發動全身,原來的所有內建該抽象工廠的具體工廠都要修改。

一個系統不應當依賴于産品類執行個體如何被建立、組合和表達的細節,這對于所有類型的工廠模式都是很重要的,使用者無須關心對象的建立過程,将對象的建立和使用解耦。

系統中有多于一個的産品系列,而每次隻使用其中某一産品系列。可以通過配置檔案等方式來使得使用者可以動态改變産品系列,也可以很友善地增加新的産品系列。

屬于同一個産品系列的産品将在一起使用,這一限制必須在系統的設計中展現出來。同一個産品系列中的産品可以是沒有任何關系的對象,但是它們都具有一些共同的限制,如Office 文檔的支援,在window xp  重視不能使用Office 2007 +的,window 7 支援0ffice 2007,是以這個限制就是作業系統對office版本的支援。

産品類型穩定,設計完成之後,不會向系統中增加新的産品類型或者删除已有的産品産品類型。

第三次需求改變:從商業化上考慮甲方要求這個軟體的某些版本隻提供導入office 2007 之前的檔案,某些版本隻支援2007以後版本。

怎麼辦呢? 這個需求開發人員拿到後一定竊喜,抽象工廠實作這種需求簡直是太容易了。配置+反射呀, 将具體工廠配置在配置檔案中,代碼中隻是用抽象并通過反射來建立工廠實進而達到動态控制的能力。

如果軟體版本中V1中隻要支援office 2007以前的文檔版本。那麼在配置檔案App.config  增加以下節點:

【設計模式】抽象工廠模式 Abstract Factory Pattern

配置完節點後在代碼中通過反射來建立工廠類, 代碼如下

輸出結果如下:

【設計模式】抽象工廠模式 Abstract Factory Pattern

如果在V1.1版本中甲方提出要求隻支援office 2007以後的版本,那麼隻需要修改配置檔案如下就可以了:

把原來的

改成:

其它地方不用做任何修改,輸出結果:

【設計模式】抽象工廠模式 Abstract Factory Pattern

繼續閱讀