抽象工廠模式(Abstract Factory)
抽象工廠模式可以說是對簡單工廠模式的一種延伸,它是圍繞一個(gè)超級工廠來創(chuàng)建其他簡單工廠,該超級工廠又稱為其他工廠的工廠。
這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。
在抽象工廠模式中,接口是負(fù)責(zé)創(chuàng)建一個(gè)相關(guān)對象的工廠,不需要顯式指定它們的類,每個(gè)生成的工廠都能按照工廠模式提供對象。
意圖
提供一個(gè)接口,用于創(chuàng)建一系列相關(guān)或有依賴關(guān)系的對象,而無需指定它們的具體類。
主要解決:主要解決接口選擇的問題。
何時(shí)使用:系統(tǒng)的產(chǎn)品有多于一個(gè)的產(chǎn)品族類,而系統(tǒng)只消費(fèi)其中某一族類的產(chǎn)品。
如何解決:在一個(gè)產(chǎn)品族里面,定義多個(gè)產(chǎn)品。
關(guān)鍵代碼:在一個(gè)工廠里聚合多個(gè)同類產(chǎn)品。
解釋
現(xiàn)實(shí)世界的例子
要?jiǎng)?chuàng)建一個(gè)王國,我們需要有共同主題的物體。精靈王國需要精靈國王、精靈城堡和精靈軍隊(duì),而獸人王國需要獸人國王、獸人城堡和獸人軍隊(duì)。王國中的對象之間存在依賴關(guān)系
簡而言之
工廠的工廠;將個(gè)別但相關(guān)/從屬工廠組合在一起而不指定其具體類別的工廠。
維基百科
The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes(抽象工廠模式提供了一種封裝一組具有共同主題的獨(dú)立工廠的方法,而無需指定它們的具體類)
程序代碼實(shí)現(xiàn)
以上面現(xiàn)實(shí)世界的王國例子。下面的類圖展示了不同具體的工廠和它們生產(chǎn)的不同具體產(chǎn)品,精靈王國的工廠生產(chǎn)精靈城堡和精靈軍隊(duì),獸人王國的工廠生產(chǎn)獸人城堡和獸人軍隊(duì)。

按照上面的類圖,我們首先來定義一些接口和實(shí)現(xiàn)類在王國中:
public interface Castle {
String getDescription();
}
public interface King {
String getDescription();
}
public interface Army {
String getDescription();
}
// Elven implementations ->
public class ElfCastle implements Castle {
static final String DESCRIPTION = "This is the Elven castle!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfKing implements King {
static final String DESCRIPTION = "This is the Elven king!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfArmy implements Army {
static final String DESCRIPTION = "This is the Elven Army!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
// Orcish implementations similarly... 獸人實(shí)現(xiàn)與上面類似
接下來我們再來定義抽象的王國工廠接口和他的具體實(shí)現(xiàn)工廠
public interface KingdomFactory {
Castle createCastle();
King createKing();
Army createArmy();
}
public class ElfKingdomFactory implements KingdomFactory {
public Castle createCastle() {
return new ElfCastle();
}
public King createKing() {
return new ElfKing();
}
public Army createArmy() {
return new ElfArmy();
}
}
public class OrcKingdomFactory implements KingdomFactory {
public Castle createCastle() {
return new OrcCastle();
}
public King createKing() {
return new OrcKing();
}
public Army createArmy() {
return new OrcArmy();
}
}
現(xiàn)在我們有了我們的抽象工廠,讓我們制作相關(guān)聯(lián)類別的家族對象,例如精靈王國工廠創(chuàng)建精靈城堡、精靈國王和精靈軍隊(duì)等
KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();
King king = factory.createKing();
Army army = factory.createArmy();
castle.getDescription(); // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!
最后我們再設(shè)計(jì)一個(gè)超級工廠來生產(chǎn)不同種類的王國工廠。在本例中我們創(chuàng)建一個(gè)FactoryMaker來生產(chǎn)ElfKingdomFactory or OrcKingdomFactory
客戶端可以通過FactoryMaker類來創(chuàng)建期望的具體王國工廠,具體的工廠將會生產(chǎn)具體的對象(軍隊(duì)、國王、城堡)
同樣在本例中我們客戶端也使用枚舉作為參數(shù)來指明我們想創(chuàng)建具體哪一類的工廠。這一塊UML關(guān)系class類圖如下:

部分重要代碼如下:
public static class FactoryMaker {
public enum KingdomType {
ELF, ORC
}
public static KingdomFactory makeFactory(KingdomType type) {
switch (type) {
case ELF:
return new ElfKingdomFactory();
case ORC:
return new OrcKingdomFactory();
default:
throw new IllegalArgumentException("KingdomType not supported.");
}
}
}
public static void main(String[] args) {
App app = new App();
LOGGER.info("Elf Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
LOGGER.info("Orc Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
}
運(yùn)行程序app輸出:
16:06:12.289 [main] INFO com.iluwatar.abstractfactory.App - Elf Kingdom
16:06:12.295 [main] INFO com.iluwatar.abstractfactory.App - This is the Elven Army!
16:06:12.295 [main] INFO com.iluwatar.abstractfactory.App - This is the Elven castle!
16:06:12.295 [main] INFO com.iluwatar.abstractfactory.App - This is the Elven king!
16:06:12.296 [main] INFO com.iluwatar.abstractfactory.App - Orc Kingdom
16:06:12.297 [main] INFO com.iluwatar.abstractfactory.App - This is the Orc Army!
16:06:12.297 [main] INFO com.iluwatar.abstractfactory.App - This is the Orc castle!
16:06:12.297 [main] INFO com.iluwatar.abstractfactory.App - This is the Orc king!
應(yīng)用場景
當(dāng)遇到如下情形時(shí),你應(yīng)該考慮使用抽象工廠模式:
- 一個(gè)系統(tǒng)應(yīng)該獨(dú)立于它的產(chǎn)品是如何創(chuàng)建、組成和表現(xiàn)的
- 系統(tǒng)應(yīng)該配置有多個(gè)產(chǎn)品系列之一
- 相關(guān)產(chǎn)品對象系列被設(shè)計(jì)為一起使用,你需要強(qiáng)制執(zhí)行此約束
- 你想提供一個(gè)產(chǎn)品類庫,你想展示的只是他們的接口,而不是他們的實(shí)現(xiàn)
- 依賴項(xiàng)的生命周期在概念上比消費(fèi)者的生命周期短
- 你需要一個(gè)運(yùn)行時(shí)值來構(gòu)造一個(gè)特定的依賴關(guān)系
- 你想決定在運(yùn)行時(shí)從一個(gè)家族中調(diào)用哪個(gè)產(chǎn)品
- 你需要通過提供一個(gè)或多個(gè)僅在運(yùn)行時(shí)已知的參數(shù),就能來解析依賴項(xiàng)
使用場景
- 應(yīng)用在運(yùn)行時(shí)需要選擇調(diào)用適當(dāng)?shù)膶?shí)現(xiàn)如FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService
- 單元測試用例編寫變的更加簡單
Java中的現(xiàn)實(shí)例子
- javax.xml.parsers.DocumentBuilderFactory
- javax.xml.transform.TransformerFactory
- javax.xml.xpath.XPathFactory
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對象。
缺點(diǎn):產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼,又要在具體的里面加代碼
寫在最后
抽象工廠模式是工廠模式的超級聚合,當(dāng)產(chǎn)品只有一個(gè)的時(shí)候,抽象工廠模式也就變成了工廠模式,當(dāng)工廠模式的產(chǎn)品變成多個(gè)時(shí),工廠模式也就變成了抽象工廠模式。
抽象工廠的模式比工廠模式要復(fù)雜很多,這也就導(dǎo)致系統(tǒng)在擴(kuò)展一個(gè)工廠或者一個(gè)產(chǎn)品時(shí),需要改動(dòng)的地方會很多,程序耦合性較高。
以上面王國的例子,假如我們要新增一個(gè)人類王國,那么我們需要新增人類王國工廠,人類城堡、人類軍隊(duì),UML類圖如下:

同樣再想想,假如我們要新增一個(gè)產(chǎn)品的時(shí)候,如一個(gè)王國除了國王、城堡、軍隊(duì)之外還應(yīng)該有瞭望塔,那么在上圖的基礎(chǔ)上我們需要修改和新增哪些接口和類呢?讀者可以自己思考一下,試著畫一下UML圖。
下一章節(jié)我將書寫單例模式
碼字不易,各位看官喜歡的話,請給點(diǎn)個(gè)贊 ??,我將持續(xù)更新,謝謝!