創(chuàng)建型SEQ3 - 抽象工廠模式 Abstract Factory Pattern

【學(xué)習(xí)難度:★★★★☆,使用頻率:★★★★★】
直接出處:抽象工廠模式
梳理和學(xué)習(xí):https://github.com/BruceOuyang/boy-design-pattern
簡書日期: 2018/03/05
簡書首頁:http://www.reibang.com/p/0fb891a7c5ed

工廠三兄弟之抽象工廠模式(一)

工廠方法模式通過引入工廠等級(jí)結(jié)構(gòu)硼身,解決了簡單工廠模式中工廠類職責(zé)太重的問題攒庵,但由于工廠方法模式中的每個(gè)工廠只生產(chǎn)一類產(chǎn)品稻励,可能會(huì)導(dǎo)致系統(tǒng)中存在大量的工廠類禀梳,勢必會(huì)增加系統(tǒng)的開銷承璃。此時(shí)利耍,我們可以考慮將一些相關(guān)的產(chǎn)品組成一個(gè)“產(chǎn)品族”,由同一個(gè)工廠來統(tǒng)一生產(chǎn)盔粹,這就是我們本文將要學(xué)習(xí)的抽象工廠模式的基本思想隘梨。

1 界面皮膚庫的初始設(shè)計(jì)

Sunny軟件公司欲開發(fā)一套界面皮膚庫,可以對(duì)Java桌面軟件進(jìn)行界面美化舷嗡。為了保護(hù)版權(quán)轴猎,該皮膚庫源代碼不打算公開,而只向用戶提供已打包為jar文件的class字節(jié)碼文件进萄。用戶在使用時(shí)可以通過菜單來選擇皮膚捻脖,不同的皮膚將提供視覺效果不同的按鈕烦秩、文本框、組合框等界面元素郎仆,其結(jié)構(gòu)示意圖如圖1所示:

圖1 界面皮膚庫結(jié)構(gòu)示意圖

該皮膚庫需要具備良好的靈活性和可擴(kuò)展性只祠,用戶可以自由選擇不同的皮膚,開發(fā)人員可以在不修改既有代碼的基礎(chǔ)上增加新的皮膚扰肌。

Sunny軟件公司的開發(fā)人員針對(duì)上述要求抛寝,決定使用工廠方法模式進(jìn)行系統(tǒng)的設(shè)計(jì),為了保證系統(tǒng)的靈活性和可擴(kuò)展性曙旭,提供一系列具體工廠來創(chuàng)建按鈕盗舰、文本框、組合框等界面元素桂躏,客戶端針對(duì)抽象工廠編程钻趋,初始結(jié)構(gòu)如圖2所示:

圖2 基于工廠方法模式的界面皮膚庫初始結(jié)構(gòu)圖

在圖2中,提供了大量工廠來創(chuàng)建具體的界面組件剂习,可以通過配置文件更換具體界面組件從而改變界面風(fēng)格蛮位。但是,此設(shè)計(jì)方案存在如下問題:

(1) 當(dāng)需要增加新的皮膚時(shí)鳞绕,雖然不要修改現(xiàn)有代碼失仁,但是需要增加大量類,針對(duì)每一個(gè)新增具體組件都需要增加一個(gè)具體工廠们何,類的個(gè)數(shù)成對(duì)增加萄焦,這無疑會(huì)導(dǎo)致系統(tǒng)越來越龐大,增加系統(tǒng)的維護(hù)成本和運(yùn)行開銷冤竹;

(2) 由于同一種風(fēng)格的具體界面組件通常要一起顯示拂封,因此需要為每個(gè)組件都選擇一個(gè)具體工廠,用戶在使用時(shí)必須逐個(gè)進(jìn)行設(shè)置鹦蠕,如果某個(gè)具體工廠選擇失誤將會(huì)導(dǎo)致界面顯示混亂冒签,雖然我們可以適當(dāng)增加一些約束語句,但客戶端代碼和配置文件都較為復(fù)雜片部。

如何減少系統(tǒng)中類的個(gè)數(shù)并保證客戶端每次始終只使用某一種風(fēng)格的具體界面組件镣衡?這是Sunny公司開發(fā)人員所面臨的兩個(gè)問題,顯然档悠,工廠方法模式無法解決這兩個(gè)問題,別著急望浩,本文所介紹的抽象工廠模式可以讓這些問題迎刃而解辖所。

工廠三兄弟之抽象工廠模式(二)

2 產(chǎn)品等級(jí)結(jié)構(gòu)與產(chǎn)品族

在工廠方法模式中具體工廠負(fù)責(zé)生產(chǎn)具體的產(chǎn)品,每一個(gè)具體工廠對(duì)應(yīng)一種具體產(chǎn)品磨德,工廠方法具有唯一性缘回,一般情況下吆视,一個(gè)具體工廠中只有一個(gè)或者一組重載的工廠方法。但是有時(shí)候我們希望一個(gè)工廠可以提供多個(gè)產(chǎn)品對(duì)象酥宴,而不是單一的產(chǎn)品對(duì)象啦吧,如一個(gè)電器工廠,它可以生產(chǎn)電視機(jī)拙寡、電冰箱授滓、空調(diào)等多種電器,而不是只生產(chǎn)某一種電器肆糕。為了更好地理解抽象工廠模式般堆,我們先引入兩個(gè)概念:

(1) 產(chǎn)品等級(jí)結(jié)構(gòu):產(chǎn)品等級(jí)結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu),如一個(gè)抽象類是電視機(jī)诚啃,其子類有海爾電視機(jī)淮摔、海信電視機(jī)、TCL電視機(jī)始赎,則抽象電視機(jī)與具體品牌的電視機(jī)之間構(gòu)成了一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)和橙,抽象電視機(jī)是父類,而具體品牌的電視機(jī)是其子類造垛。

(2) 產(chǎn)品族:在抽象工廠模式中胃碾,產(chǎn)品族是指由同一個(gè)工廠生產(chǎn)的,位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中的一組產(chǎn)品筋搏,如海爾電器工廠生產(chǎn)的海爾電視機(jī)仆百、海爾電冰箱,海爾電視機(jī)位于電視機(jī)產(chǎn)品等級(jí)結(jié)構(gòu)中奔脐,海爾電冰箱位于電冰箱產(chǎn)品等級(jí)結(jié)構(gòu)中俄周,海爾電視機(jī)、海爾電冰箱構(gòu)成了一個(gè)產(chǎn)品族髓迎。

產(chǎn)品等級(jí)結(jié)構(gòu)與產(chǎn)品族示意圖如圖3所示:

圖3 產(chǎn)品族與產(chǎn)品等級(jí)結(jié)構(gòu)示意圖

在圖3中峦朗,不同顏色的多個(gè)正方形、圓形和橢圓形分別構(gòu)成了三個(gè)不同的產(chǎn)品等級(jí)結(jié)構(gòu)排龄,而相同顏色的正方形波势、圓形和橢圓形構(gòu)成了一個(gè)產(chǎn)品族,每一個(gè)形狀對(duì)象都位于某個(gè)產(chǎn)品族橄维,并屬于某個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)尺铣。圖3中一共有五個(gè)產(chǎn)品族,分屬于三個(gè)不同的產(chǎn)品等級(jí)結(jié)構(gòu)争舞。我們只要指明一個(gè)產(chǎn)品所處的產(chǎn)品族以及它所屬的等級(jí)結(jié)構(gòu)凛忿,就可以唯一確定這個(gè)產(chǎn)品。

當(dāng)系統(tǒng)所提供的工廠生產(chǎn)的具體產(chǎn)品并不是一個(gè)簡單的對(duì)象竞川,而是多個(gè)位于不同產(chǎn)品等級(jí)結(jié)構(gòu)店溢、屬于不同類型的具體產(chǎn)品時(shí)就可以使用抽象工廠模式叁熔。抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形式。抽象工廠模式與工廠方法模式最大的區(qū)別在于床牧,工廠方法模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)荣回,而抽象工廠模式需要面對(duì)多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),一個(gè)工廠等級(jí)結(jié)構(gòu)可以負(fù)責(zé)多個(gè)不同產(chǎn)品等級(jí)結(jié)構(gòu)中的產(chǎn)品對(duì)象的創(chuàng)建戈咳。當(dāng)一個(gè)工廠等級(jí)結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級(jí)結(jié)構(gòu)的一個(gè)產(chǎn)品族中的所有對(duì)象時(shí)心软,抽象工廠模式比工廠方法模式更為簡單、更有效率除秀。

抽象工廠模式示意圖如圖4所示:

圖4 抽象工廠模式示意圖

在圖4中糯累,每一個(gè)具體工廠可以生產(chǎn)屬于一個(gè)產(chǎn)品族的所有產(chǎn)品,例如生產(chǎn)顏色相同的正方形册踩、圓形和橢圓形泳姐,所生產(chǎn)的產(chǎn)品又位于不同的產(chǎn)品等級(jí)結(jié)構(gòu)中。如果使用工廠方法模式暂吉,圖4所示結(jié)構(gòu)需要提供15個(gè)具體工廠胖秒,而使用抽象工廠模式只需要提供5個(gè)具體工廠,極大減少了系統(tǒng)中類的個(gè)數(shù)慕的。

工廠三兄弟之抽象工廠模式(三)

3 抽象工廠模式概述

抽象工廠模式為創(chuàng)建一組對(duì)象提供了一種解決方案阎肝。與工廠方法模式相比,抽象工廠模式中的具體工廠不只是創(chuàng)建一種產(chǎn)品肮街,它負(fù)責(zé)創(chuàng)建一族產(chǎn)品风题。抽象工廠模式定義如下:

抽象工廠模式(Abstract Factory Pattern):提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無須指定它們具體的類嫉父。抽象工廠模式又稱為Kit模式沛硅,它是一種對(duì)象創(chuàng)建型模式。

在抽象工廠模式中绕辖,每一個(gè)具體工廠都提供了多個(gè)工廠方法用于產(chǎn)生多種不同類型的產(chǎn)品摇肌,這些產(chǎn)品構(gòu)成了一個(gè)產(chǎn)品族,抽象工廠模式結(jié)構(gòu)如圖5所示:

圖5 抽象工廠模式結(jié)構(gòu)圖

在抽象工廠模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:

  • AbstractFactory(抽象工廠):它聲明了一組用于創(chuàng)建一族產(chǎn)品的方法仪际,每一個(gè)方法對(duì)應(yīng)一種產(chǎn)品围小。

  • ConcreteFactory(具體工廠):它實(shí)現(xiàn)了在抽象工廠中聲明的創(chuàng)建產(chǎn)品的方法,生成一組具體產(chǎn)品树碱,這些產(chǎn)品構(gòu)成了一個(gè)產(chǎn)品族肯适,每一個(gè)產(chǎn)品都位于某個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)中。

  • AbstractProduct(抽象產(chǎn)品):它為每種產(chǎn)品聲明接口赴恨,在抽象產(chǎn)品中聲明了產(chǎn)品所具有的業(yè)務(wù)方法疹娶。

  • ConcreteProduct(具體產(chǎn)品):它定義具體工廠生產(chǎn)的具體產(chǎn)品對(duì)象,實(shí)現(xiàn)抽象產(chǎn)品接口中聲明的業(yè)務(wù)方法伦连。

在抽象工廠中聲明了多個(gè)工廠方法雨饺,用于創(chuàng)建不同類型的產(chǎn)品,抽象工廠可以是接口惑淳,也可以是抽象類或者具體類额港,其典型代碼如下所示:

abstract class AbstractFactory {  
    
    //工廠方法一
    public abstract AbstractProductA createProductA(); 
    
    //工廠方法二
    public abstract AbstractProductB createProductB();   
    //……  
}

具體工廠實(shí)現(xiàn)了抽象工廠,每一個(gè)具體的工廠方法可以返回一個(gè)特定的產(chǎn)品對(duì)象歧焦,而同一個(gè)具體工廠所創(chuàng)建的產(chǎn)品對(duì)象構(gòu)成了一個(gè)產(chǎn)品族移斩。對(duì)于每一個(gè)具體工廠類,其典型代碼如下所示:

class ConcreteFactory1 extends AbstractFactory {  
    //工廠方法一  
    public AbstractProductA createProductA() {  
        return new ConcreteProductA1();  
    }  

    //工廠方法二  
    public AbstractProductB createProductB() {  
        return new ConcreteProductB1();  
    }  

    //……  
}

與工廠方法模式一樣绢馍,抽象工廠模式也可為每一種產(chǎn)品提供一組重載的工廠方法向瓷,以不同的方式對(duì)產(chǎn)品對(duì)象進(jìn)行創(chuàng)建。

思考

抽象工廠模式是否符合“開閉原則”舰涌?【從增加新的產(chǎn)品等級(jí)結(jié)構(gòu)和增加新的產(chǎn)品族兩方面進(jìn)行思考猖任。】

工廠三兄弟之抽象工廠模式(四)

4 完整解決方案

Sunny公司開發(fā)人員使用抽象工廠模式來重構(gòu)界面皮膚庫的設(shè)計(jì)瓷耙,其基本結(jié)構(gòu)如圖6所示:

圖6 界面皮膚庫結(jié)構(gòu)圖

在圖6中朱躺,SkinFactory接口充當(dāng)抽象工廠,其子類SpringSkinFactory和SummerSkinFactory充當(dāng)具體工廠搁痛,接口Button长搀、TextField和ComboBox充當(dāng)抽象產(chǎn)品,其子類SpringButton鸡典、SpringTextField源请、SpringComboBox和SummerButton、SummerTextField彻况、SummerComboBox充當(dāng)具體產(chǎn)品谁尸。完整代碼如下所示:

//在本實(shí)例中我們對(duì)代碼進(jìn)行了大量簡化,實(shí)際使用時(shí)疗垛,界面組件的初始化代碼較為復(fù)雜症汹,還需要使用JDK中一些已有類,為了突出核心代碼贷腕,在此只提供框架代碼和演示輸出背镇。  
//按鈕接口:抽象產(chǎn)品  
interface Button {  
    public void display();  
}  

//Spring按鈕類:具體產(chǎn)品  
class SpringButton implements Button {  
    public void display() {  
        System.out.println("顯示淺綠色按鈕。");  
    }  
}  

//Summer按鈕類:具體產(chǎn)品  
class SummerButton implements Button {  
    public void display() {  
        System.out.println("顯示淺藍(lán)色按鈕泽裳。");  
    }     
}  

//文本框接口:抽象產(chǎn)品  
interface TextField {  
    public void display();  
}  

//Spring文本框類:具體產(chǎn)品  
class SpringTextField implements TextField {  
    public void display() {  
        System.out.println("顯示綠色邊框文本框瞒斩。");  
    }  
}  

//Summer文本框類:具體產(chǎn)品  
class SummerTextField implements TextField {  
    public void display() {  
        System.out.println("顯示藍(lán)色邊框文本框。");  
    }     
}  

//組合框接口:抽象產(chǎn)品  
interface ComboBox {  
    public void display();  
}  

//Spring組合框類:具體產(chǎn)品  
class SpringComboBox implements ComboBox {  
    public void display() {  
        System.out.println("顯示綠色邊框組合框涮总。");  
    }  
}  

//Summer組合框類:具體產(chǎn)品  
class SummerComboBox implements ComboBox {  
    public void display() {  
        System.out.println("顯示藍(lán)色邊框組合框胸囱。");  
    }     
}  

//界面皮膚工廠接口:抽象工廠  
interface SkinFactory {  
    public Button createButton();  
    public TextField createTextField();  
    public ComboBox createComboBox();  
}  

//Spring皮膚工廠:具體工廠  
class SpringSkinFactory implements SkinFactory {  
    public Button createButton() {  
        return new SpringButton();  
    }  

    public TextField createTextField() {  
        return new SpringTextField();  
    }  

    public ComboBox createComboBox() {  
        return new SpringComboBox();  
    }  
}  

//Summer皮膚工廠:具體工廠  
class SummerSkinFactory implements SkinFactory {  
    public Button createButton() {  
        return new SummerButton();  
    }  

    public TextField createTextField() {  
        return new SummerTextField();  
    }  

    public ComboBox createComboBox() {  
        return new SummerComboBox();  
    }  
}

為了讓系統(tǒng)具備良好的靈活性和可擴(kuò)展性,我們引入了工具類XMLUtil和配置文件瀑梗,其中烹笔,XMLUtil類的代碼如下所示:

import javax.xml.parsers.*;  
import org.w3c.dom.*;  
import org.xml.sax.SAXException;  
import java.io.*;  

public class XMLUtil {  
//該方法用于從XML配置文件中提取具體類類名裳扯,并返回一個(gè)實(shí)例對(duì)象  
    public static Object getBean() {  
        try {  
            //創(chuàng)建文檔對(duì)象  
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder builder = dFactory.newDocumentBuilder();  
            Document doc;                             
            doc = builder.parse(new File("config.xml"));   

            //獲取包含類名的文本節(jié)點(diǎn)  
            NodeList nl = doc.getElementsByTagName("className");  
            Node classNode=nl.item(0).getFirstChild();  
            String cName=classNode.getNodeValue();  

            //通過類名生成實(shí)例對(duì)象并將其返回  
            Class c=Class.forName(cName);  
            Object obj=c.newInstance();  
            return obj;  
        }     
        catch(Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}

配置文件config.xml中存儲(chǔ)了具體工廠類的類名,代碼如下所示:

<?xml version="1.0"?>  
<config>  
    <className>SpringSkinFactory</className>  
</config>  

編寫如下客戶端測試代碼:

class Client {  
    public static void main(String args[]) {  
        //使用抽象層定義  
        SkinFactory factory;  
        Button bt;  
        TextField tf;  
        ComboBox cb;  
        factory = (SkinFactory)XMLUtil.getBean();  
        bt = factory.createButton();  
        tf = factory.createTextField();  
        cb = factory.createComboBox();  
        bt.display();  
        tf.display();  
        cb.display();  
    }  
}

編譯并運(yùn)行程序谤职,輸出結(jié)果如下:

顯示淺綠色按鈕饰豺。
顯示綠色邊框文本框。
顯示綠色邊框組合框允蜈。

如果需要更換皮膚冤吨,只需修改配置文件即可,在實(shí)際環(huán)境中饶套,我們可以提供可視化界面漩蟆,例如菜單或者窗口來修改配置文件,用戶無須直接修改配置文件妓蛮。如果需要增加新的皮膚怠李,只需增加一族新的具體組件并對(duì)應(yīng)提供一個(gè)新的具體工廠,修改配置文件即可使用新的皮膚仔引,原有代碼無須修改扔仓,符合“開閉原則”。

擴(kuò)展

在真實(shí)項(xiàng)目開發(fā)中咖耘,我們通常會(huì)為配置文件提供一個(gè)可視化的編輯界面翘簇,類似Struts框架中的struts.xml編輯器,大家可以自行開發(fā)一個(gè)簡單的圖形化工具來修改配置文件儿倒,實(shí)現(xiàn)真正的純界面操作版保。

工廠三兄弟之抽象工廠模式(五)

5 “開閉原則”的傾斜性

Sunny公司使用抽象工廠模式設(shè)計(jì)了界面皮膚庫,該皮膚庫可以較為方便地增加新的皮膚夫否,但是現(xiàn)在遇到一個(gè)非常嚴(yán)重的問題:由于設(shè)計(jì)時(shí)考慮不全面彻犁,忘記為單選按鈕(RadioButton)提供不同皮膚的風(fēng)格化顯示,導(dǎo)致無論選擇哪種皮膚凰慈,單選按鈕都顯得那么“格格不入”汞幢。Sunny公司的設(shè)計(jì)人員決定向系統(tǒng)中增加單選按鈕,但是發(fā)現(xiàn)原有系統(tǒng)居然不能夠在符合“開閉原則”的前提下增加新的組件微谓,原因是抽象工廠SkinFactory中根本沒有提供創(chuàng)建單選按鈕的方法森篷,如果需要增加單選按鈕,首先需要修改抽象工廠接口SkinFactory豺型,在其中新增聲明創(chuàng)建單選按鈕的方法仲智,然后逐個(gè)修改具體工廠類,增加相應(yīng)方法以實(shí)現(xiàn)在不同的皮膚中創(chuàng)建單選按鈕姻氨,此外還需要修改客戶端钓辆,否則單選按鈕無法應(yīng)用于現(xiàn)有系統(tǒng)。

怎么辦?答案是抽象工廠模式無法解決該問題前联,這也是抽象工廠模式最大的缺點(diǎn)功戚。在抽象工廠模式中,增加新的產(chǎn)品族很方便蛀恩,但是增加新的產(chǎn)品等級(jí)結(jié)構(gòu)很麻煩疫铜,抽象工廠模式的這種性質(zhì)稱為“開閉原則”的傾斜性茂浮∷唬“開閉原則”要求系統(tǒng)對(duì)擴(kuò)展開放,對(duì)修改封閉席揽,通過擴(kuò)展達(dá)到增強(qiáng)其功能的目的顽馋,對(duì)于涉及到多個(gè)產(chǎn)品族與多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)的系統(tǒng),其功能增強(qiáng)包括兩方面:

(1) 增加產(chǎn)品族:對(duì)于增加新的產(chǎn)品族幌羞,抽象工廠模式很好地支持了“開閉原則”寸谜,只需要增加具體產(chǎn)品并對(duì)應(yīng)增加一個(gè)新的具體工廠,對(duì)已有代碼無須做任何修改属桦。

(2) 增加新的產(chǎn)品等級(jí)結(jié)構(gòu):對(duì)于增加新的產(chǎn)品等級(jí)結(jié)構(gòu)熊痴,需要修改所有的工廠角色,包括抽象工廠類聂宾,在所有的工廠類中都需要增加生產(chǎn)新產(chǎn)品的方法果善,違背了“開閉原則”。

正因?yàn)槌橄蠊S模式存在“開閉原則”的傾斜性系谐,它以一種傾斜的方式來滿足“開閉原則”巾陕,為增加新產(chǎn)品族提供方便,但不能為增加新產(chǎn)品結(jié)構(gòu)提供這樣的方便纪他,因此要求設(shè)計(jì)人員在設(shè)計(jì)之初就能夠全面考慮鄙煤,不會(huì)在設(shè)計(jì)完成之后向系統(tǒng)中增加新的產(chǎn)品等級(jí)結(jié)構(gòu),也不會(huì)刪除已有的產(chǎn)品等級(jí)結(jié)構(gòu)茶袒,否則將會(huì)導(dǎo)致系統(tǒng)出現(xiàn)較大的修改梯刚,為后續(xù)維護(hù)工作帶來諸多麻煩。

6 抽象工廠模式總結(jié)

抽象工廠模式是工廠方法模式的進(jìn)一步延伸薪寓,由于它提供了功能更為強(qiáng)大的工廠類并且具備較好的可擴(kuò)展性亡资,在軟件開發(fā)中得以廣泛應(yīng)用,尤其是在一些框架和API類庫的設(shè)計(jì)中预愤,例如在Java語言的AWT(抽象窗口工具包)中就使用了抽象工廠模式沟于,它使用抽象工廠模式來實(shí)現(xiàn)在不同的操作系統(tǒng)中應(yīng)用程序呈現(xiàn)與所在操作系統(tǒng)一致的外觀界面。抽象工廠模式也是在軟件開發(fā)中最常用的設(shè)計(jì)模式之一植康。

  1. 主要優(yōu)點(diǎn)

抽象工廠模式的主要優(yōu)點(diǎn)如下:

(1) 抽象工廠模式隔離了具體類的生成旷太,使得客戶并不需要知道什么被創(chuàng)建。由于這種隔離,更換一個(gè)具體工廠就變得相對(duì)容易供璧,所有的具體工廠都實(shí)現(xiàn)了抽象工廠中定義的那些公共接口存崖,因此只需改變具體工廠的實(shí)例,就可以在某種程度上改變整個(gè)軟件系統(tǒng)的行為睡毒。

(2) 當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí)来惧,它能夠保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。

(3) 增加新的產(chǎn)品族很方便演顾,無須修改已有系統(tǒng)供搀,符合“開閉原則”。

  1. 主要缺點(diǎn)

抽象工廠模式的主要缺點(diǎn)如下:

增加新的產(chǎn)品等級(jí)結(jié)構(gòu)麻煩钠至,需要對(duì)原有系統(tǒng)進(jìn)行較大的修改葛虐,甚至需要修改抽象層代碼,這顯然會(huì)帶來較大的不便棉钧,違背了“開閉原則”屿脐。

  1. 適用場景

在以下情況下可以考慮使用抽象工廠模式:

(1) 一個(gè)系統(tǒng)不應(yīng)當(dāng)依賴于產(chǎn)品類實(shí)例如何被創(chuàng)建、組合和表達(dá)的細(xì)節(jié)宪卿,這對(duì)于所有類型的工廠模式都是很重要的的诵,用戶無須關(guān)心對(duì)象的創(chuàng)建過程,將對(duì)象的創(chuàng)建和使用解耦佑钾。

(2) 系統(tǒng)中有多于一個(gè)的產(chǎn)品族西疤,而每次只使用其中某一產(chǎn)品族〈位妫可以通過配置文件等方式來使得用戶可以動(dòng)態(tài)改變產(chǎn)品族瘪阁,也可以很方便地增加新的產(chǎn)品族。

(3) 屬于同一個(gè)產(chǎn)品族的產(chǎn)品將在一起使用邮偎,這一約束必須在系統(tǒng)的設(shè)計(jì)中體現(xiàn)出來管跺。同一個(gè)產(chǎn)品族中的產(chǎn)品可以是沒有任何關(guān)系的對(duì)象,但是它們都具有一些共同的約束禾进,如同一操作系統(tǒng)下的按鈕和文本框豁跑,按鈕與文本框之間沒有直接關(guān)系,但它們都是屬于某一操作系統(tǒng)的泻云,此時(shí)具有一個(gè)共同的約束條件:操作系統(tǒng)的類型艇拍。

(4) 產(chǎn)品等級(jí)結(jié)構(gòu)穩(wěn)定,設(shè)計(jì)完成之后宠纯,不會(huì)向系統(tǒng)中增加新的產(chǎn)品等級(jí)結(jié)構(gòu)或者刪除已有的產(chǎn)品等級(jí)結(jié)構(gòu)卸夕。

練習(xí)

Sunny軟件公司欲推出一款新的手機(jī)游戲軟件,該軟件能夠支持Symbian婆瓜、Android和Windows Mobile等多個(gè)智能手機(jī)操作系統(tǒng)平臺(tái)快集,針對(duì)不同的手機(jī)操作系統(tǒng)贡羔,該游戲軟件提供了不同的游戲操作控制(OperationController)類和游戲界面控制(InterfaceController)類,并提供相應(yīng)的工廠類來封裝這些類的初始化過程个初。軟件要求具有較好的擴(kuò)展性以支持新的操作系統(tǒng)平臺(tái)乖寒,為了滿足上述需求,試采用抽象工廠模式對(duì)其進(jìn)行設(shè)計(jì)院溺。

練習(xí)會(huì)在我的github上做掉

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末楣嘁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子珍逸,更是在濱河造成了極大的恐慌逐虚,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弄息,死亡現(xiàn)場離奇詭異痊班,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)摹量,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馒胆,“玉大人缨称,你說我怎么就攤上這事∽S兀” “怎么了睦尽?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長型雳。 經(jīng)常有香客問我当凡,道長,這世上最難降的妖魔是什么纠俭? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任沿量,我火速辦了婚禮,結(jié)果婚禮上冤荆,老公的妹妹穿的比我還像新娘朴则。我一直安慰自己,他們只是感情好钓简,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布乌妒。 她就那樣靜靜地躺著,像睡著了一般外邓。 火紅的嫁衣襯著肌膚如雪撤蚊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天损话,我揣著相機(jī)與錄音侦啸,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛匹中,可吹牛的內(nèi)容都是我干的夏漱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼顶捷,長吁一口氣:“原來是場噩夢啊……” “哼挂绰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起服赎,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤葵蒂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后重虑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體践付,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年缺厉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了永高。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡提针,死狀恐怖命爬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辐脖,我是刑警寧澤饲宛,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站嗜价,受9級(jí)特大地震影響艇抠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜久锥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一家淤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奴拦,春花似錦媒鼓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至暂氯,卻和暖如春潮模,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痴施。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工擎厢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留究流,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓动遭,卻偏偏與公主長得像芬探,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厘惦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容