一、抽象工廠模式的本質(zhì)
抽象工廠模式封裝同一產(chǎn)品族(產(chǎn)品族可以認(rèn)為是相關(guān)的產(chǎn)品,如電腦和鼠標(biāo)鍵盤可稱為一個產(chǎn)品族)的創(chuàng)建細(xì)節(jié),工廠方法抽象了一個產(chǎn)品等級的創(chuàng)建細(xì)節(jié)(產(chǎn)品等級可以認(rèn)為是同類產(chǎn)品按照不同的指標(biāo)分成了不同的等級,如電腦的低配版、高配版、旗艦版等),一個產(chǎn)品族里面有不同類的產(chǎn)品(如電子產(chǎn)品族里面有手機、電腦、平板等,其中電子產(chǎn)品可認(rèn)為是一個抽象的產(chǎn)品族,而手機、電腦、平板可認(rèn)為是不同的產(chǎn)品等級或者類,手機產(chǎn)品類中又有蘋果、華為、小米等),抽象工廠模式對產(chǎn)品族進(jìn)行了抽象,抽象工廠就是在產(chǎn)品族這一層進(jìn)行了抽象,也就是說她能夠創(chuàng)建的產(chǎn)品種類更多。
抽象工廠模式的本質(zhì)是通過提供統(tǒng)一的接口,保證在同一工廠中創(chuàng)建產(chǎn)品族中的不同產(chǎn)品(產(chǎn)品類/產(chǎn)品等級)。

二、抽象工廠模式目的
抽象工廠模式的目的是通過抽象工廠創(chuàng)建一系列相關(guān)的產(chǎn)品類對象,而無需指定其具體產(chǎn)品類。如上圖所示,抽象工廠能夠創(chuàng)建小米手機類對象或者其它產(chǎn)品類對象,而不需要客戶端顯示的使用new關(guān)鍵字來創(chuàng)建相關(guān)產(chǎn)品類的對象。同時,抽象工廠統(tǒng)一負(fù)責(zé)一個產(chǎn)品族中的不同產(chǎn)品等級的產(chǎn)品,這樣就實現(xiàn)了對創(chuàng)建產(chǎn)品類對象的統(tǒng)一封裝,也就是說,通過具體的抽象工廠類可以創(chuàng)建同一產(chǎn)品族中不同的產(chǎn)品等級的產(chǎn)品類對象。
三、示例場景
某個電腦公司的在線購物網(wǎng)站可售賣不同廠家(如小米、華為、蘋果)的電腦、手機、平板等電子產(chǎn)品,網(wǎng)站需要為客戶提供各種電子的配置信息查看功能,每當(dāng)用戶想查看某個電子產(chǎn)品配置時,需要給出該電子產(chǎn)品生產(chǎn)日期以及價格等信息。
注意事項:每個廠家都有可能隨時新增新的產(chǎn)品。
四、代碼實現(xiàn)及對比
從上述示例場景中可以看出,每個廠家都會出售手機、電腦、平板,根據(jù)抽象工廠模式的設(shè)計思想,我們可以分別將手機、電腦和平板設(shè)置為產(chǎn)品等級,將每個廠家的所有手機、電腦、平板設(shè)置為產(chǎn)品族,然后,通過抽象工廠統(tǒng)一提供統(tǒng)一產(chǎn)品族(廠家)中產(chǎn)品等級中的某個產(chǎn)品(如手機)。
IPad類定義(平板的抽象定義,此處用接口實現(xiàn))
public interface IPad {
void Drawing(String picName);
void PlayingFilm(String filmName);
}
XiaomiPad類定義(具體平板產(chǎn)品類)
public class XiaomiPad implements IPad{
@Override
public void Drawing(String picName) {
System.out.println("Drawing a picture with 小米 Pad: " + picName);
}
@Override
public void PlayingFilm(String filmName) {
System.out.println("Watching a file with 小米 Pad: " + filmName);
}
}
HuaweiPad類定義(具體平板產(chǎn)品類)
public class HuaweiPad implements IPad{
@Override
public void Drawing(String picName) {
System.out.println("Drawing a picture with 華為 Pad: " + picName);
}
@Override
public void PlayingFilm(String filmName) {
System.out.println("Watching a file with 華為 Pad: " + filmName);
}
}
IPhone類定義(手機的抽象定義,此處用接口實現(xiàn))
public interface IPhone {
void calling(String number);
void sendMessage(String msg);
}
XiaomiPhone類定義(具體手機產(chǎn)品類)
public class XiaomiPhone implements IPhone{
@Override
public void calling(String num) {
System.out.println("Make calls using your 小米 phone: "+num);
}
@Override
public void sendMessage(String msg) {
System.out.println("Send messages using your 小米 phone: "+msg);
}
}
HuaweiPhone類定義(具體手機產(chǎn)品類)
public class HuaweiPhone implements IPhone{
@Override
public void calling(String num) {
System.out.println("Make calls using your 華為 phone: "+ num);
}
@Override
public void sendMessage(String msg) {
System.out.println("Send messages using your 華為 phone: "+msg);
}
}
抽象工廠的抽象類定義(此處用接口實現(xiàn))
public interface IAbstractFactory {
IPad createPad();
IPhone createPhone();
}
xiaomi工廠的定義(實現(xiàn)抽象工廠,提供產(chǎn)品族中各種產(chǎn)品的具體創(chuàng)建)
public class XiaomiFactory implements IAbstractFactory{
@Override
public IPad createPad() {
return new XiaomiPad();
}
@Override
public IPhone createPhone() {
return new XiaomiPhone();
}
}
Huawei工廠的定義(實現(xiàn)抽象工廠,提供產(chǎn)品族中各種產(chǎn)品的具體創(chuàng)建)
public class HuaweiFactory implements IAbstractFactory{
@Override
public IPad createPad() {
return new HuaweiPad();
}
@Override
public IPhone createPhone() {
return new HuaweiPhone();
}
}
客戶端類定義
public class main {
public static void main(String[] args) {
System.out.println("Abstract Factory Pattern: client.");
/*使用抽象工廠模式來創(chuàng)建產(chǎn)品等級中的某類產(chǎn)品類對象*/
IAbstractFactory xiaomiFactory = new XiaomiFactory();
IPhone xiaomiPhone = xiaomiFactory.createIphone();
xiaomiPhone.calling("1111111111111");
xiaomiPhone.sendMessage("How are you?");
IPad xiaomiPad = xiaomiFactory.createPad();
xiaomiPad.PlayingFilm("Fast & Furious 9");
xiaomiPad.Drawing("Mona Lisa");
System.out.println("-----------------------------------------------------");
IAbstractFactory huaweiFactory = new HuaweiFactory();
IPhone huaweiPhone = huaweiFactory.createIphone();
huaweiPhone.calling("222222222");
huaweiPhone.sendMessage("Do you have a nice day?");
IPad huaweiPad = huaweiFactory.createPad();
huaweiPad.Drawing("The Last Supper");
huaweiPad.PlayingFilm("流浪地球");
}
}
注意:這里的具體的產(chǎn)品類的創(chuàng)建還可以配合工廠方法/簡單工廠模式來實現(xiàn),此處為了避免與工廠方法/簡單工廠模式產(chǎn)生混淆,在具體產(chǎn)品工廠定義中就直接使用new關(guān)鍵字來創(chuàng)建具體的產(chǎn)品類了。
五、抽象工廠模式的UML類圖

抽象工廠模式的關(guān)鍵類與相互的關(guān)系如上圖所示。
IPad和IPhone為抽象類,定義了具體產(chǎn)品類的屬性和方法;
HuaweiPad、XiaomiPad、HuaweiPhone、XiaomiPhone這四個類分別是上述兩個抽象類的具體實現(xiàn)類,實現(xiàn)抽象類中定義的方法,如手機的打電話方法、平板的看電影方法;
IAbstractFactory類為抽象工廠類,定義了具體產(chǎn)品工廠需要提供的產(chǎn)品類創(chuàng)建的方法,需要包含整個產(chǎn)品族中所有產(chǎn)品類的創(chuàng)建方法;
XiaomiFactory和HuaweiFactory這兩個類就是IAbstractFactory抽象類的具體實現(xiàn)類,分別實現(xiàn)了各自產(chǎn)品族中不同產(chǎn)品類的創(chuàng)建方法;
然后,客戶端類通過創(chuàng)建具體工廠類開啟具體產(chǎn)品類實例的創(chuàng)建,具體產(chǎn)品類實例對象的創(chuàng)建過程如下:
第一步:創(chuàng)建抽象工廠的具體實現(xiàn)類實例,如 IAbstractFactory xiaomiFactory = new XiaomiFactory();,這時候,小米工廠就可以創(chuàng)建小米這個產(chǎn)品族中不同的產(chǎn)品了;
第二步:利用具體工廠創(chuàng)建具體產(chǎn)品類實例對象,如IPhone xiaomiPhone = xiaomiFactory.createIphone();具體產(chǎn)品創(chuàng)建完成。

六、抽象工廠模式的優(yōu)缺點
(1)優(yōu)點
抽象工廠模式隔離了具體類的生產(chǎn),使得客戶并不需要了解具體產(chǎn)品如何被創(chuàng)建的。
當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象。
-
增加新的具體工廠和產(chǎn)品族很方便,無須修改已有系統(tǒng),符合“開閉原則”。
新增產(chǎn)品族時,類圖變化.png
如上圖所示,當(dāng)需要新增產(chǎn)品族的時候,直接添加相關(guān)的具體產(chǎn)品類和工廠類即可。
(2)缺點
- 增加新的產(chǎn)品等級結(jié)構(gòu)很復(fù)雜,需要修改抽象工廠和所有的具體工廠類,對“開閉原則”的支持呈現(xiàn)傾斜性。

如上圖所示,當(dāng)需要新增產(chǎn)品時,需要修改響應(yīng)的工廠類(抽象和具體工廠類都需要修改),違反“開閉原則”。
