抽象工廠模式是工廠方法模式的升級(jí)版本,主要是引入了一個(gè)產(chǎn)品族的概念,將針對單一產(chǎn)品升級(jí)到了針對多個(gè)產(chǎn)品品種和產(chǎn)品分類。
原文鏈接:
http://tianweili.github.io/blog/2015/03/11/abstract-factory-pattern/
介紹抽象工廠模式定義:PRovide an interface for creating families of related or dependent objects without specifying their concrete classes.為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個(gè)接口,而且無需指定他們具體的類。
抽象工廠模式是工廠方法模式的升級(jí)版本,主要是引入了一個(gè)產(chǎn)品族的概念,將針對單一產(chǎn)品升級(jí)到了針對多個(gè)產(chǎn)品品種和產(chǎn)品分類。
UML類圖{% img /design-pattern/abstract-factory-uml.png %}
左邊的UML圖并不復(fù)雜,主要包括2個(gè)抽象產(chǎn)品和一個(gè)抽象工廠。兩個(gè)具體實(shí)現(xiàn)工廠各對應(yīng)創(chuàng)建兩個(gè)不同類別產(chǎn)品。
產(chǎn)品族和產(chǎn)品等級(jí)抽象工廠模式關(guān)鍵點(diǎn)在于有了多個(gè)產(chǎn)品族。
如上圖所示,ProductA1和ProductA2就是屬于一個(gè)產(chǎn)品族。ProductA1和ProductB1分別屬于兩個(gè)不同的產(chǎn)品族。上面的UML圖中有兩個(gè)產(chǎn)品族。
有幾個(gè)抽象產(chǎn)品類就有幾個(gè)產(chǎn)品族。
有幾個(gè)產(chǎn)品族,在工廠中就有幾個(gè)創(chuàng)建方法。
繼承于同一個(gè)抽象產(chǎn)品類的屬于不同的產(chǎn)品等級(jí)。
ProductA1和ProductA2就是兩個(gè)產(chǎn)品等級(jí)。ProductA1和ProductB1屬于同一個(gè)產(chǎn)品等級(jí)。
有幾個(gè)產(chǎn)品等級(jí),就有幾個(gè)實(shí)現(xiàn)工廠類。
在每個(gè)工廠類中,實(shí)現(xiàn)了不同產(chǎn)品族的創(chuàng)建方法。
代碼示例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(); }}客戶端調(diào)用
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(); }}在上面的客戶端調(diào)用代碼中,沒有與具體的產(chǎn)品實(shí)現(xiàn)類有關(guān)的代碼。所以在需要某個(gè)具體產(chǎn)品的時(shí)候,只需要知道與之對應(yīng)的工廠來生產(chǎn)就可以了。
與工廠方法模式的區(qū)別抽象工廠模式與工廠方法模式的關(guān)鍵不同在于引入了一個(gè)產(chǎn)品族的概念,工廠方法模式相當(dāng)于只有一個(gè)產(chǎn)品族,而抽象工廠模式有多個(gè)產(chǎn)品族。
在有多個(gè)產(chǎn)品族的時(shí)候只能使用抽象工廠模式了。
針對多個(gè)產(chǎn)品族,每個(gè)實(shí)現(xiàn)工廠都有相應(yīng)的創(chuàng)建對應(yīng)產(chǎn)品的方法。而工廠方法模式中實(shí)現(xiàn)工廠中只會(huì)有一個(gè)創(chuàng)建產(chǎn)品的方法。
優(yōu)點(diǎn)高層模塊只需要知道生產(chǎn)相應(yīng)產(chǎn)品的工廠類是誰,就能由工廠創(chuàng)建相應(yīng)的產(chǎn)品對象。而他不用關(guān)心具體產(chǎn)品生產(chǎn)過程,符合迪米特法則。只依賴抽象產(chǎn)品,符合依賴倒置原則。使用產(chǎn)品子類替換產(chǎn)品父類,符合里氏替換原則。
不同產(chǎn)品族之間的約束放在工廠類中來實(shí)現(xiàn),不對外公開,封裝性好。
想較于工廠方法模式,可以應(yīng)付產(chǎn)品更為復(fù)雜的場合。
在產(chǎn)品等級(jí)結(jié)構(gòu)層面上符合開閉原則,增加一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)擴(kuò)展性好。
缺點(diǎn)在產(chǎn)品族層面上不符合開閉原則,增加一個(gè)產(chǎn)品族,即相當(dāng)于增加一個(gè)抽象產(chǎn)品時(shí),需要修改大量的其他實(shí)現(xiàn)工廠,在產(chǎn)品族層面上擴(kuò)展性不好。
適用場景當(dāng)涉及到多個(gè)產(chǎn)品族的時(shí)候,就需要使用抽象工廠模式了。
應(yīng)用實(shí)例開發(fā)軟件應(yīng)用多個(gè)操作系統(tǒng)據(jù)說抽象工廠模式最初應(yīng)用于多個(gè)操作系統(tǒng)軟件開發(fā)上,比如要開發(fā)一個(gè)系統(tǒng)桌面軟件,要應(yīng)用到Windows和linux操作系統(tǒng)上。那么對于這樣的情況我們是不是要分別為兩種操作系統(tǒng)開發(fā)不同的軟件呢?當(dāng)然不是。對于開發(fā)一個(gè)桌面軟件來說分為界面UI和功能代碼等,那么就可以應(yīng)用抽象工廠模式了,界面UI和功能代碼都分別為Windows和Linux開發(fā)不同的一套,然后利用工廠在需要Windows的時(shí)候調(diào)用創(chuàng)建相應(yīng)的Windows的界面UI和功能代碼。
不同網(wǎng)站爬蟲解析做過一個(gè)爬蟲工程,需求是這樣的,公司有多個(gè)站點(diǎn),想要去根據(jù)搜索關(guān)鍵字獲取它們在搜索頁面一些要素,比如廣告、文章、產(chǎn)品等信息。那么針對這種需求就采用了抽象工廠模式。首先將廣告、文章等分別都作為一個(gè)產(chǎn)品族,每個(gè)網(wǎng)站都是一個(gè)產(chǎn)品等級(jí)。這樣抽象出來的解析廣告類、解析文章類等抽象接口,由每個(gè)具體產(chǎn)品去實(shí)現(xiàn)某個(gè)站點(diǎn)的解析廣告,另一個(gè)產(chǎn)品族的具體產(chǎn)品去實(shí)現(xiàn)解析文章類,將具體解析過程封裝在了產(chǎn)品內(nèi)部。再使用相應(yīng)的工廠來創(chuàng)建一個(gè)個(gè)產(chǎn)品族內(nèi)的產(chǎn)品。
關(guān)鍵邏輯刪減版類圖如下
{% img /design-pattern/sitecrawler-uml.png %}
這樣就實(shí)現(xiàn)了良好的封裝性,高層模塊想調(diào)用知道某個(gè)網(wǎng)站的一些統(tǒng)計(jì)分析數(shù)據(jù)時(shí),只需要知道相應(yīng)的工廠來生產(chǎn)就行了,不需要知道具體的實(shí)現(xiàn)過程和復(fù)雜的處理邏輯。在產(chǎn)品等級(jí)也就是網(wǎng)站層面上擴(kuò)展性好,后來有新增站點(diǎn)的時(shí)候,直接增加產(chǎn)品等級(jí),實(shí)現(xiàn)相應(yīng)的抽象產(chǎn)品類,再增加一個(gè)具體實(shí)現(xiàn)工廠就好了。
不過它的缺點(diǎn)是在產(chǎn)品族也就是想新增解析需求的時(shí)候擴(kuò)展性不好,比如后來想增加對搜索關(guān)鍵詞后的首頁文章內(nèi)容進(jìn)行統(tǒng)計(jì),以便查看匹配度時(shí)。就需要增加一個(gè)產(chǎn)品族即抽象產(chǎn)品模塊,需要修改每個(gè)工廠的代碼。
作者:李天煒
原文鏈接:http://tianweili.github.io/blog/2015/03/11/abstract-factory-pattern/
轉(zhuǎn)載請注明作者和文章出處,謝謝。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注