標籤:
再來介紹一下抽象原廠模式(Abstact Factory Pattern),也是建立型模式之一,上篇部落客要介紹了Factory 方法模式。抽象原廠模式和Factory 方法模式稍有區別。Factory 方法模式中工廠類生產出來的產品都是具體的,也就是說每個工廠都會生產某一種具體的產品,但是如果工廠類中所生產出來的產品是多種多樣的,Factory 方法模式也就不再適用了,就要使用抽象原廠模式了。
抽象原廠模式的起源或者最早的應用,是對不同作業系統的圖形化解決方案,比如在不同作業系統中的按鈕和文字框的不同處理,展示效果也不一樣,對於每一個作業系統,其本身構成一個工廠類,而按鈕與文字框控制項構成一個產品類,兩種產品類兩種變化,各自有自己的特性,比如 Windows,Unix 和 Mac OS 下的 Button 和 Text 等。所以據此,我們可以初步構建架構:
然後對於 Windows 系統來說需要產生的是 WindowsButton 和 WindowsText 產品類對象,其他兩個系統一樣也需要對應的對象。為了達到“為建立一組相關或者是相互依賴的對象提供一個介面,而不需要指定它們的具體類”的鬆散耦合原則,這時使用抽象原廠模式就非常契合。
PS:對技術感興趣的同鞋加群544645972一起交流。
設計模式總目錄
java/android 設計模式學習筆記目錄
特點
抽象原廠模式(Abstact Factory Pattern)提供一個介面,用於建立相關或依賴對象的家族,而不需要明確指明具體類。
和Factory 方法模式一樣,抽象原廠模式依然符合“針對抽象編程,不針對具體類編程”的原則,將用戶端和具體類解耦,增加擴充性,契合設計模式中的依賴倒置原則和裡氏替換原則。
UML類圖
這裡以上面的不同作業系統的圖形化解決方案為例來畫出 uml 類圖(貌似圖片寬度被固定死了,在新的標籤頁中開啟該圖片即可),
雖然抽象原廠模式的類繁多,但是主要還是分為 4 類:
- AbstractFactory:抽象工廠角色(對應 IFactory 介面),它聲明了一組用於建立不同產品的方法,每一個方法對應一種產品,中的 IFactory 介面就有 createButton 和 createText 方法用於建立 IButton 對象和 IText 對象。
- ConcreteFactory:具體工廠角色(對應 WindowFactory,UnixFactory 和 MacOSFactory 類),它實現了在抽象工廠中定義的建立產品的方法,產生一組具體產品,這些產品構成一個產品種類,每一個產品都位於某個產品等級結構中。
- AbstractProduct:抽象產品角色(對應 IButton 和 IText 介面),他定義了幾種產品的基本行為。
- ConcreteProduct:具體產品角色(對應WindowsButton 和 WindowsText 等 6 個實作類別),它定義具體工廠生產的具體產品對象,實現抽象產品介面中聲明的業務方法。
這裡用的是一個執行個體的 uml 類圖,對應的抽象原廠模式的 uml 類圖只要把其中的角色換一個名字就可以了,是一樣的。
樣本與源碼
我們直接根據上面的 uml 類圖直接構造四個角色:
產品相關類
產品類主要是 IButton 介面和其實現子類,IText 介面和其實現子類。IButton 介面和其子類:
IButton.class
public interface IButton { void show();}
WindowsButton.class
public class WindowsButton implements IButton { @Override public void show() { Log.e("show", "this is a Windows button"); }}
UnixButton.class
public class UnixButton implements IButton{ @Override public void show() { Log.e("show", "this is a Unix button"); }}
MacOSButton.class
public class MacOSButton implements IButton{ @Override public void show() { Log.e("show", "this is a MacOS button"); }}
IText 介面和其實現子類:
IText.class
public interface IText { void show();}
WindowsText.class
public class WindowsText implements IText{ @Override public void show() { Log.e("show", "this is a Windows text"); }}
UnixText.class
public class UnixText implements IText{ @Override public void show() { Log.e("show", "this is a Unix text"); }}
MacOSText.class
public class MacOSText implements IText{ @Override public void show() { Log.e("show", "this is a MacOS text"); }}
工廠相關類
上面定義完產品的相關類之後就要定義工廠的相關類了,工廠類的作用主要是用來建立對應的兩個產品種類的對象:
IFactory.class
public interface IFactory { /** * 產生對應按鈕 */ IButton createButton(); /** * 產生對應文字 */ IText createText();}
WindowsFactory.class
public class WindowsFactory implements IFactory { @Override public IButton createButton() { return new WindowsButton(); } @Override public IText createText() { return new WindowsText(); }}
UnixFactory.class
public class UnixFactory implements IFactory{ @Override public IButton createButton() { return new UnixButton(); } @Override public IText createText() { return new UnixText(); }}
MacOSFactory.class
public class MacOSFactory implements IFactory{ @Override public IButton createButton() { return new MacOSButton(); } @Override public IText createText() { return new MacOSText(); }}
測試
最後的測試程式也很簡單:
@Overridepublic void onClick(View v) { switch (v.getId()) { case R.id.btn_Windows: WindowsFactory windowsFactory = new WindowsFactory(); windowsFactory.createButton().show(); windowsFactory.createText().show(); break; case R.id.btn_Unix: UnixFactory unixFactory = new UnixFactory(); unixFactory.createButton().show(); unixFactory.createText().show(); break; case R.id.btn_MacOS: MacOSFactory macOSFactory = new MacOSFactory(); macOSFactory.createButton().show(); macOSFactory.createText().show(); break; }}
對象的日誌也能夠成功的列印:
總結
抽象原廠模式在 Android 源碼中的實現相對來說是比較少的,其中一個比較確切的例子是 Android 底層對 MediaPlayer 的建立,具體類圖如下所示(在新的標籤頁中開啟該圖片即可):
四種 MediaPlayerFactory 分別會產生不同的 MediaPlayer 基類:StagefrightPlayer、NuPlayerDriver、MidFile 和 TestPlayerStub ,四者均繼承於MediaPlayerBase 。
抽象工廠的優點有很多,一個顯著的優點是分離介面與實現,用戶端使用抽象工廠來建立需要的對象,它根本就不知道具體的實現是誰,用戶端只是面向產品的介面編程而已,使其從具體的產品實現中解耦,同時基於介面與實現的分離,使抽象原廠模式在切換產品類時更加靈活、容易。
當然缺點也是很明顯的,第一個也是最明顯的就是類檔案的大大增多,第二個是如果要擴充新的產品類,就需要去修改抽象工廠類的最下層介面,這就會導致所有的具體工廠類均會被修改。
抽象原廠模式與Factory 方法模式對比
其實對比一下兩種模式的 uml 圖,就可以發現其實Factory 方法模式是潛伏在抽象原廠模式中的,抽象工廠中的每個方法都可以單獨抽出來作為一個Factory 方法。抽象工廠的任務是定義一個負責建立一組產品的介面,這個介面內的每個方法都負責建立一個具體產品,同時我們利用實現抽象工廠的子類來提供這些具體的做法,所以在抽象工廠中利用Factory 方法來實現生產方法是相當自然的做法。這麼一對比,可以知道抽象原廠模式比原廠模式的一個優點就是在它可以將一群相關的產品集合起來。
對比一下,使用情境也就清楚了:當需要建立產品家族和想讓製造的相關產品集合起來時,使用抽象原廠模式;當僅僅想把客戶代碼從需要執行個體化的具體類中解耦,或者如果目前還不明確將來需要執行個體化哪些具體類時,可以使用Factory 方法模式。
源碼下載
https://github.com/zhaozepeng/Design-Patterns/tree/master/AbstactFactoryPattern
引用
http://blog.csdn.net/jason0539/article/details/44976775
https://en.wikipedia.org/wiki/Abstract_factory_pattern
java/android 設計模式學習筆記(4)---抽象原廠模式