抽象工廠模式是工廠方法模式的升級版本,主要是引入了一個產品族的概念,將針對單一產品升級到了針對多個產品品種和產品分類。java
原文連接:git
http://tianweili.github.io/blog/2015/03/11/abstract-factory-pattern/github
抽象工廠模式定義:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.爲建立一組相關或相互依賴的對象提供一個接口,並且無需指定他們具體的類。ide
抽象工廠模式是工廠方法模式的升級版本,主要是引入了一個產品族的概念,將針對單一產品升級到了針對多個產品品種和產品分類。網站
{% img /design-pattern/abstract-factory-uml.png %}操作系統
左邊的UML圖並不複雜,主要包括2個抽象產品和一個抽象工廠。兩個具體實現工廠各對應建立兩個不一樣類別產品。code
抽象工廠模式關鍵點在於有了多個產品族。對象
如上圖所示,ProductA1和ProductA2就是屬於一個產品族。ProductA1和ProductB1分別屬於兩個不一樣的產品族。上面的UML圖中有兩個產品族。blog
有幾個抽象產品類就有幾個產品族。繼承
有幾個產品族,在工廠中就有幾個建立方法。
繼承於同一個抽象產品類的屬於不一樣的產品等級。
ProductA1和ProductA2就是兩個產品等級。ProductA1和ProductB1屬於同一個產品等級。
有幾個產品等級,就有幾個實現工廠類。
在每一個工廠類中,實現了不一樣產品族的建立方法。
public interface AbstractProductA { public void method(); } public class ProductA1 implements AbstractProductA{ public void method() { System.out.println("This is ProductA1."); } } public class ProductA2 implements AbstractProductA{ public void method() { System.out.println("This is ProductA2."); } } public interface AbstractProductB { public void method(); } public class ProductB1 implements AbstractProductB{ public void method() { System.out.println("This is ProductB1."); } } public class ProductB2 implements AbstractProductB{ public void method() { System.out.println("This is ProductB2."); } } public interface AbstractFactory { public AbstractProductA createProductA(); public AbstractProductB createProductB(); } public class Factory1 implements AbstractFactory{ public AbstractProductA createProductA() { return new ProductA1(); } public AbstractProductB createProductB() { return new ProductB1(); } } public class Factory2 implements AbstractFactory{ public AbstractProductA createProductA() { return new ProductA2(); } public AbstractProductB createProductB() { return new ProductB2(); } }
客戶端調用
public class Client { public static void main(String[] args) { AbstractFactory factory1 = new Factory1(); AbstractFactory factory2 = new Factory2(); AbstractProductA productA1 = factory1.createProductA(); AbstractProductB productB1 = factory1.createProductB(); AbstractProductA productA2 = factory2.createProductA(); AbstractProductB productB2 = factory2.createProductB(); } }
在上面的客戶端調用代碼中,沒有與具體的產品實現類有關的代碼。因此在須要某個具體產品的時候,只須要知道與之對應的工廠來生產就能夠了。
抽象工廠模式與工廠方法模式的關鍵不一樣在於引入了一個產品族的概念,工廠方法模式至關於只有一個產品族,而抽象工廠模式有多個產品族。
在有多個產品族的時候只能使用抽象工廠模式了。
針對多個產品族,每一個實現工廠都有相應的建立對應產品的方法。而工廠方法模式中實現工廠中只會有一個建立產品的方法。
高層模塊只須要知道生產相應產品的工廠類是誰,就能由工廠建立相應的產品對象。而他不用關心具體產品生產過程,符合迪米特法則。只依賴抽象產品,符合依賴倒置原則。使用產品子類替換產品父類,符合里氏替換原則。
不一樣產品族之間的約束放在工廠類中來實現,不對外公開,封裝性好。
想較於工廠方法模式,能夠應付產品更爲複雜的場合。
在產品等級結構層面上符合開閉原則,增長一個產品等級結構擴展性好。
在產品族層面上不符合開閉原則,增長一個產品族,即至關於增長一個抽象產品時,須要修改大量的其餘實現工廠,在產品族層面上擴展性很差。
當涉及到多個產品族的時候,就須要使用抽象工廠模式了。
聽說抽象工廠模式最初應用於多個操做系統軟件開發上,好比要開發一個系統桌面軟件,要應用到Windows和Linux操做系統上。那麼對於這樣的狀況咱們是否是要分別爲兩種操做系統開發不一樣的軟件呢?固然不是。對於開發一個桌面軟件來講分爲界面UI和功能代碼等,那麼就能夠應用抽象工廠模式了,界面UI和功能代碼都分別爲Windows和Linux開發不一樣的一套,而後利用工廠在須要Windows的時候調用建立相應的Windows的界面UI和功能代碼。
作過一個爬蟲工程,需求是這樣的,公司有多個站點,想要去根據搜索關鍵字獲取它們在搜索頁面一些要素,好比廣告、文章、產品等信息。那麼針對這種需求就採用了抽象工廠模式。首先將廣告、文章等分別都做爲一個產品族,每一個網站都是一個產品等級。這樣抽象出來的解析廣告類、解析文章類等抽象接口,由每一個具體產品去實現某個站點的解析廣告,另外一個產品族的具體產品去實現解析文章類,將具體解析過程封裝在了產品內部。再使用相應的工廠來建立一個個產品族內的產品。
關鍵邏輯刪減版類圖以下
{% img /design-pattern/sitecrawler-uml.png %}
這樣就實現了良好的封裝性,高層模塊想調用知道某個網站的一些統計分析數據時,只須要知道相應的工廠來生產就好了,不須要知道具體的實現過程和複雜的處理邏輯。在產品等級也就是網站層面上擴展性好,後來有新增站點的時候,直接增長產品等級,實現相應的抽象產品類,再增長一個具體實現工廠就行了。
不過它的缺點是在產品族也就是想新增解析需求的時候擴展性很差,好比後來想增長對搜索關鍵詞後的首頁文章內容進行統計,以便查看匹配度時。就須要增長一個產品族即抽象產品模塊,須要修改每一個工廠的代碼。
做者:李天煒
原文連接:http://tianweili.github.io/blog/2015/03/11/abstract-factory-pattern/
轉載請註明做者和文章出處,謝謝。