在講解抽象工廠前我們首先需要了解兩個概念:
產(chǎn)品等級結(jié)構(gòu):產(chǎn)品的等級結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu)。如果一個抽象類是電視機,其子類有海爾電視機、海信電視機、創(chuàng)維電視機,則抽象電視機與具體品牌的電視機之間構(gòu)成了一個產(chǎn)品等級結(jié)構(gòu),抽象電視機是父類,而具體品牌的電視機是其子類。
-
產(chǎn)品族:在抽象工廠模式中,產(chǎn)品族是指由一個工廠生產(chǎn)的,位于不同產(chǎn)品等級結(jié)構(gòu)中的一組產(chǎn)品,如海爾電器生產(chǎn)的海爾電視機、海爾冰箱,海爾電視機位于電視機產(chǎn)品等級結(jié)構(gòu)中,海爾冰箱位于冰箱產(chǎn)品等級結(jié)構(gòu)中。海爾電視機,海爾冰箱構(gòu)成了一個產(chǎn)品族。
產(chǎn)品結(jié)構(gòu)&產(chǎn)品族
圖中一共有四個產(chǎn)品族,分布于三個不同的產(chǎn)品等級結(jié)構(gòu)中。只要指明一個產(chǎn)品所處的產(chǎn)品族以及它所屬的等級結(jié)構(gòu),就可以唯一的確定這個產(chǎn)品。
引進抽象工廠模式
所謂的抽象工廠是指一個工廠等級結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級結(jié)構(gòu)的一個產(chǎn)品族中的所有對象。如果用圖來描述的話,如下圖:

定義
抽象工廠模式(Abstract Factory),提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們的具體類。
結(jié)構(gòu)

抽象工廠包含如下角色:
-
IFactory:抽象工廠
抽象工廠定義了一個接口,所有的具體工廠都必須實現(xiàn)此接口,這個接口包含一組方法用來生產(chǎn)產(chǎn)品。 -
ConCreteFactory:具體工廠
具體工廠實現(xiàn)生成不同的具體產(chǎn)品家族,要創(chuàng)建一個產(chǎn)品,客戶端主要使用其中一個工廠而不需要實例化任何產(chǎn)品對象。 -
IProduct:抽象產(chǎn)品
不同的抽象產(chǎn)品為不同的產(chǎn)品家族,每一個具體的工廠都能實現(xiàn)一整套的產(chǎn)品 -
ConcreteProduct:具體產(chǎn)品
對抽象產(chǎn)品的具體分類的實現(xiàn)
場景示例
說起抽象工廠不得不讓人想起位于各大城市中魚龍混雜的電子城。只有你想不到的,沒有他們生產(chǎn)不出來的。 500塊的Iphone你買到過嗎?你見到過裝有安卓系統(tǒng)、小米攝像頭的蘋果手機嗎?下面讓我們一起來見識一下裝有安卓手機系統(tǒng)的蘋果手機是怎么在電子城生產(chǎn)出來的。
手機賣家,也就是我們的手機工廠,使用主板、攝像頭、手機外殼就能組裝出一臺手機:
public interface IFactory {
MainBoard createMainBoard();
CameraLens createCameraLens();
Case createCase();
}
然后無良賣家根據(jù)組裝流程給組裝了三種類型的手機
/**
* 蘋果手機
*/
public class AppleFactory implements IFactory {
@Override
public MainBoard createMainBoard() {
return new IosMainBoard();
}
@Override
public CameraLens createCameraLens() {
return new IosCameraLens();
}
@Override
public Case createCase() {
return new IosCase();
}
}
/**
* 組裝Android手機
*/
public class AndroidFactory implements IFactory {
@Override
public MainBoard createMainBoard() {
return new AndroidMainBoard();
}
@Override
public CameraLens createCameraLens() {
return new AndroidCameraLens();
}
@Override
public Case createCase() {
return new AndroidCase();
}
}
/**
* 組裝裝有安卓操作系統(tǒng)、安卓攝像頭的蘋果手機
*/
public class AndroidAppleFactory implements IFactory {
@Override
public MainBoard createMainBoard() {
return new AndroidMainBoard();
}
@Override
public CameraLens createCameraLens() {
return new AndroidCameraLens();
}
@Override
public Case createCase() {
return new IosCase();
}
}
不同的配件產(chǎn)品
public class AndroidCameraLens implements CameraLens {
@Override
public String getCameraLens() {
return "安卓攝像頭";
}
}
public class AndroidCase implements Case {
@Override
public String getCase() {
return "安卓手機外殼";
}
}
public class AndroidMainBoard implements MainBoard {
@Override
public String getMainBoard() {
return "安卓主板";
}
}
public class IosCameraLens implements CameraLens {
@Override
public String getCameraLens() {
return "蘋果攝像頭";
}
}
public class IosCase implements Case {
@Override
public String getCase() {
return "蘋果手機外殼";
}
}
public class IosMainBoard implements MainBoard {
@Override
public String getMainBoard() {
return "蘋果手機主板";
}
}
然后顧客來買手機
public class App {
public static void main(String[] args) {
IFactory factory = new AppleFactory();
String mainBoard = factory.createMainBoard().getMainBoard();
String cameraLens = factory.createCameraLens().getCameraLens();
String aCase = factory.createCase().getCase();
System.out.println(String.format("手機配件:%s、%s、%s,售價:12888", mainBoard, cameraLens, aCase));
}
}
騷年,新出的Apple XRS 手機配件:裝有蘋果主板、蘋果攝像頭、蘋果手機外殼,售價:12888,要不要來一臺?
嫌貴啊,沒關(guān)系,我這有新出的安卓機:
public class App {
public static void main(String[] args) {
IFactory factory = new AndroidFactory();
String mainBoard = factory.createMainBoard().getMainBoard();
String cameraLens = factory.createCameraLens().getCameraLens();
String aCase = factory.createCase().getCase();
System.out.println(String.format("手機配件:%s、%s、%s,售價:4000", mainBoard, cameraLens, aCase));
}
}
手機配件:裝有安卓主板、安卓攝像頭、安卓手機外殼,售價:4000,超高性價比,只要4000,考不考慮入手?
這樣吧,騷年,你我相遇也是有緣,我這新弄了一臺二手Apple,便宜出你,你看怎么樣
public class App {
public static void main(String[] args) {
IFactory factory = new AndroidAppleFactory();
String mainBoard = factory.createMainBoard().getMainBoard();
String cameraLens = factory.createCameraLens().getCameraLens();
String aCase = factory.createCase().getCase();
System.out.println(String.format("手機配件:%s、%s、%s,售價:4000", mainBoard, cameraLens, aCase));
}
}
手機配件:安卓主板、安卓攝像頭、蘋果手機外殼,售價:500 只要500,95成新,怎么樣。
勿占小便宜?。。?/strong>
優(yōu)點
抽象工廠模式隔離了具體類的生成,使得客戶并不需要知道什么被創(chuàng)建。由于這種隔離,更換一個具體工廠就變得相對容易。所有的具體工廠都實現(xiàn)了抽象工廠中定義的那些公共接口,因此只需改變具體工廠的實例,就可以在某種程度上改變整個軟件系統(tǒng)的行為。另外,應(yīng)用抽象工廠模式可以實現(xiàn)高內(nèi)聚低耦合的設(shè)計目的,因此抽象工廠模式得到了廣泛的應(yīng)用。
當一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能夠保證客戶端始終只使用同一個產(chǎn)品族中的對象。這對一些需要根據(jù)當前環(huán)境來決定其行為的軟件系統(tǒng)來說,是一種非常實用的設(shè)計模式。
增加新的具體工廠和產(chǎn)品族很方便,無須修改已有系統(tǒng),符合
開閉原則。
缺點
在添加新的產(chǎn)品對象時,難以擴展抽象工廠來生產(chǎn)新種類的產(chǎn)品,這是因為在抽象工廠角色中規(guī)定了所有可能被創(chuàng)建的產(chǎn)品集合,要支持新種類的產(chǎn)品就意味著要對該接口進行擴展,而這將涉及到對抽象工廠角色及其所有子類的修改,顯然會帶來較大的不便。
開閉原則的傾斜性(增加新的工廠和產(chǎn)品族容易,增加新的產(chǎn)品等級結(jié)構(gòu)麻煩)。
應(yīng)用場景
- 當需要創(chuàng)建的對象是一系列相互關(guān)聯(lián)或相互依賴的產(chǎn)品族時,便可以使用抽象工廠模式。
- 系統(tǒng)中有多于一個的產(chǎn)品族,而每次只使用其中某一產(chǎn)品族。
- 屬于同一個產(chǎn)品族的產(chǎn)品將在一起使用,這一約束必須在系統(tǒng)的設(shè)計中體現(xiàn)出來。
- 系統(tǒng)提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。
簡單來講,就是一個繼承體系中,如果存在著多個等級結(jié)構(gòu)(即存在著多個抽象類),并且分屬各個等級結(jié)構(gòu)中的實現(xiàn)類之間存在著一定的關(guān)聯(lián)或者約束,就可以使用抽象工廠模式。假如各個等級結(jié)構(gòu)中的實現(xiàn)類之間不存在關(guān)聯(lián)或約束,則使用多個獨立的工廠來對產(chǎn)品進行創(chuàng)建,則更合適一點。
“開閉原則”的傾斜性
“開閉原則”要求系統(tǒng)對擴展開放,對修改封閉,通過擴展達到增強其功能的目的。對于涉及到多個產(chǎn)品族與多個產(chǎn)品等級結(jié)構(gòu)的系統(tǒng),其功能增強包括兩方面:
增加產(chǎn)品族:對于增加新的產(chǎn)品族,工廠方法模式很好的支持了“開閉原則”,對于新增加的產(chǎn)品族,只需要對應(yīng)增加一個新的具體工廠即可,對已有代碼無須做任何修改。
增加新的產(chǎn)品等級結(jié)構(gòu):對于增加新的產(chǎn)品等級結(jié)構(gòu),需要修改所有的工廠角色,包括抽象工廠類,在所有的工廠類中都需要增加生產(chǎn)新產(chǎn)品的方法,不能很好地支持“開閉原則”。
抽象工廠模式的這種性質(zhì)稱為“開閉原則”的傾斜性,抽象工廠模式以一種傾斜的方式支持增加新的產(chǎn)品,它為新產(chǎn)品族的增加提供方便,但不能為新的產(chǎn)品等級結(jié)構(gòu)的增加提供這樣的方便。
工廠模式的退化
- 當抽象工廠模式中每一個具體工廠類只創(chuàng)建一個產(chǎn)品對象,也就是只存在一個產(chǎn)品等級結(jié)構(gòu)時,抽象工廠模式退化成工廠方法模式;當工廠方法模式中抽象工廠與具體工廠合并,提供一個統(tǒng)一的工廠來創(chuàng)建產(chǎn)品對象,并將創(chuàng)建對象的工廠方法設(shè)計為靜態(tài)方法時,工廠方法模式退化成簡單工廠模式。
總結(jié)
產(chǎn)品等級結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu)關(guān)系。產(chǎn)品族即由一個共產(chǎn)生產(chǎn)的,位于不同產(chǎn)品等級結(jié)構(gòu)中的一組產(chǎn)品。
抽象工廠模式提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們的具體類。抽象工廠模式又稱為Kit模式,屬于對象創(chuàng)建型模式。
抽象工廠包含四個角色:抽象工廠、具體工廠、抽象產(chǎn)品、具體產(chǎn)品。
抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠模式與工廠方法模式最大的區(qū)別在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu),而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)。抽象工廠中利用工廠方法實現(xiàn)生產(chǎn)方法是很普遍的做法。
抽象工廠模式的主要優(yōu)點是隔離了具體類的生成,使得客戶并不需要知道什么被創(chuàng)建,而且每次可以通過具體工廠類創(chuàng)建一個產(chǎn)品族中的多個對象,增加或者替換產(chǎn)品族比較方便,增加新的具體工廠和產(chǎn)品族很方便;主要缺點在于增加新的產(chǎn)品等級結(jié)構(gòu)很復(fù)雜,需要修改抽象工廠和所有的具體工廠類,對“開閉原則”的支持呈現(xiàn)傾斜性。
抽象工廠模式適用情況包括:一個系統(tǒng)不應(yīng)當依賴于產(chǎn)品類實例如何被創(chuàng)建、組合和表達的細節(jié);系統(tǒng)中有多于一個的產(chǎn)品族,而每次只使用其中某一產(chǎn)品族;屬于同一個產(chǎn)品族的產(chǎn)品將在一起使用;系統(tǒng)提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。
