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

二、抽象工廠模式目的
抽象工廠模式的目的是通過(guò)抽象工廠創(chuàng)建一系列相關(guān)的產(chǎn)品類對(duì)象,而無(wú)需指定其具體產(chǎn)品類。如上圖所示,抽象工廠能夠創(chuàng)建小米手機(jī)類對(duì)象或者其它產(chǎn)品類對(duì)象,而不需要客戶端顯示的使用new關(guān)鍵字來(lái)創(chuàng)建相關(guān)產(chǎn)品類的對(duì)象。同時(shí),抽象工廠統(tǒng)一負(fù)責(zé)一個(gè)產(chǎn)品族中的不同產(chǎn)品等級(jí)的產(chǎn)品,這樣就實(shí)現(xiàn)了對(duì)創(chuàng)建產(chǎn)品類對(duì)象的統(tǒng)一封裝,也就是說(shuō),通過(guò)具體的抽象工廠類可以創(chuàng)建同一產(chǎn)品族中不同的產(chǎn)品等級(jí)的產(chǎn)品類對(duì)象。
三、示例場(chǎng)景
某個(gè)電腦公司的在線購(gòu)物網(wǎng)站可售賣不同廠家(如小米、華為、蘋(píng)果)的電腦、手機(jī)、平板等電子產(chǎn)品,網(wǎng)站需要為客戶提供各種電子的配置信息查看功能,每當(dāng)用戶想查看某個(gè)電子產(chǎn)品配置時(shí),需要給出該電子產(chǎn)品生產(chǎn)日期以及價(jià)格等信息。
注意事項(xiàng):每個(gè)廠家都有可能隨時(shí)新增新的產(chǎn)品。
四、代碼實(shí)現(xiàn)及對(duì)比
從上述示例場(chǎng)景中可以看出,每個(gè)廠家都會(huì)出售手機(jī)、電腦、平板,根據(jù)抽象工廠模式的設(shè)計(jì)思想,我們可以分別將手機(jī)、電腦和平板設(shè)置為產(chǎn)品等級(jí),將每個(gè)廠家的所有手機(jī)、電腦、平板設(shè)置為產(chǎn)品族,然后,通過(guò)抽象工廠統(tǒng)一提供統(tǒng)一產(chǎn)品族(廠家)中產(chǎn)品等級(jí)中的某個(gè)產(chǎn)品(如手機(jī))。
IPad類定義(平板的抽象定義,此處用接口實(shí)現(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類定義(手機(jī)的抽象定義,此處用接口實(shí)現(xiàn))
public interface IPhone {
void calling(String number);
void sendMessage(String msg);
}
XiaomiPhone類定義(具體手機(jī)產(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類定義(具體手機(jī)產(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);
}
}
抽象工廠的抽象類定義(此處用接口實(shí)現(xiàn))
public interface IAbstractFactory {
IPad createPad();
IPhone createPhone();
}
xiaomi工廠的定義(實(shí)現(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工廠的定義(實(shí)現(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.");
/*使用抽象工廠模式來(lái)創(chuàng)建產(chǎn)品等級(jí)中的某類產(chǎn)品類對(duì)象*/
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)建還可以配合工廠方法/簡(jiǎn)單工廠模式來(lái)實(shí)現(xiàn),此處為了避免與工廠方法/簡(jiǎn)單工廠模式產(chǎn)生混淆,在具體產(chǎn)品工廠定義中就直接使用new關(guān)鍵字來(lái)創(chuàng)建具體的產(chǎn)品類了。
五、抽象工廠模式的UML類圖

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

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

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