Java抽象工廠模式

概述

每一個模式都是針對一定問題的解決方案囚灼。抽象工廠模式與工廠方法模式的最大區(qū)別就在于螃宙,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu)雁社;而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)。
  在學(xué)習(xí)抽象工廠具體實例之前久脯,應(yīng)該明白兩個重要的概念:產(chǎn)品族和產(chǎn)品等級纳胧。
  所謂產(chǎn)品族,是指位于不同產(chǎn)品等級結(jié)構(gòu)中帘撰,功能相關(guān)聯(lián)的產(chǎn)品組成的家族跑慕。比如AMD的主板、芯片組摧找、CPU組成一個家族核行,Intel的主板、芯片組蹬耘、CPU組成一個家族芝雪。而這兩個家族都來自于三個產(chǎn)品等級:主板、芯片組综苔、CPU惩系。一個等級結(jié)構(gòu)是由相同的結(jié)構(gòu)的產(chǎn)品組成,示意圖如下:



  顯然如筛,每一個產(chǎn)品族中含有產(chǎn)品的數(shù)目堡牡,與產(chǎn)品等級結(jié)構(gòu)的數(shù)目是相等的。產(chǎn)品的等級結(jié)構(gòu)與產(chǎn)品族將產(chǎn)品按照不同方向劃分杨刨,形成一個二維的坐標(biāo)系晤柄。橫軸表示產(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)具有平行的結(jié)構(gòu)。因此怕品,如果采用工廠方法模式妇垢,就勢必要使用三個獨立的工廠等級結(jié)構(gòu)來對付這三個產(chǎn)品等級結(jié)構(gòu)。由于這三個產(chǎn)品等級結(jié)構(gòu)的相似性肉康,會導(dǎo)致三個平行的工廠等級結(jié)構(gòu)闯估。隨著產(chǎn)品等級結(jié)構(gòu)的數(shù)目的增加,工廠方法模式所給出的工廠等級結(jié)構(gòu)的數(shù)目也會隨之增加吼和。如下圖:



  那么涨薪,是否可以使用同一個工廠等級結(jié)構(gòu)來對付這些相同或者極為相似的產(chǎn)品等級結(jié)構(gòu)呢?當(dāng)然可以的炫乓,而且這就是抽象工廠模式的好處刚夺。同一個工廠等級結(jié)構(gòu)負(fù)責(zé)三個不同產(chǎn)品等級結(jié)構(gòu)中的產(chǎn)品對象的創(chuàng)建。

  可以看出末捣,一個工廠等級結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級結(jié)構(gòu)的一個產(chǎn)品族中的所有對象侠姑。顯然,這時候抽象工廠模式比簡單工廠模式箩做、工廠方法模式更有效率莽红。對應(yīng)于每一個產(chǎn)品族都有一個具體工廠。而每一個具體工廠負(fù)責(zé)創(chuàng)建屬于同一個產(chǎn)品族邦邦,但是分屬于不同等級結(jié)構(gòu)的產(chǎn)品安吁。

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

抽象工廠模式是對象的創(chuàng)建模式,它是工廠方法模式的進(jìn)一步推廣燃辖。
  假設(shè)一個子系統(tǒng)需要一些產(chǎn)品對象鬼店,而這些產(chǎn)品又屬于一個以上的產(chǎn)品等級結(jié)構(gòu)。那么為了將消費這些產(chǎn)品對象的責(zé)任和創(chuàng)建這些產(chǎn)品對象的責(zé)任分割開來黔龟,可以引進(jìn)抽象工廠模式薪韩。這樣的話,消費產(chǎn)品的一方不需要直接參與產(chǎn)品的創(chuàng)建工作捌锭,而只需要向一個公用的工廠接口請求所需要的產(chǎn)品俘陷。
  通過使用抽象工廠模式,可以處理具有相同(或者相似)等級結(jié)構(gòu)中的多個產(chǎn)品族中的產(chǎn)品對象的創(chuàng)建問題观谦。如下圖所示:

  

  由于這兩個產(chǎn)品族的等級結(jié)構(gòu)相同拉盾,因此使用同一個工廠族也可以處理這兩個產(chǎn)品族的創(chuàng)建問題豁状,這就是抽象工廠模式倒得。
  根據(jù)產(chǎn)品角色的結(jié)構(gòu)圖,就不難給出工廠角色的結(jié)構(gòu)設(shè)計圖夭禽。

  可以看出霞掺,每一個工廠角色都有兩個工廠方法,分別負(fù)責(zé)創(chuàng)建分屬不同產(chǎn)品等級結(jié)構(gòu)的產(chǎn)品對象讹躯。

  

源代碼

/**
 * 處理器產(chǎn)品接口
 */
public interface Cpu {

    public void showMsg();

}

/**
 * 主板產(chǎn)品接口
 */
public interface Mainboard {

    public void showMsg();

}

/**
 * 具體的產(chǎn)品菩彬,intel處理器
 */
public class IntelCpu implements Cpu {
    @Override
    public void showMsg() {
        System.out.println("處理器:intel");
    }
}

/**
 * 具體的產(chǎn)品,amd處理器
 */
public class AmdCpu implements Cpu {
    @Override
    public void showMsg() {
        System.out.println("處理器:amd");
    }
}

/**
 * 具體的產(chǎn)品潮梯,intel主板
 */
public class IntelMainboard implements Mainboard {
    @Override
    public void showMsg() {
        System.out.println("主板:intel");
    }
}

/**
 * 具體的產(chǎn)品骗灶,amd主板
 */
public class AmdMainboard implements Mainboard {
    @Override
    public void showMsg() {
        System.out.println("主板:amd");
    }
}
/**
 * 抽象工廠
 */
public interface AbstractFactory {

    /**
     * 創(chuàng)建cpu
     * @return
     */
    public Cpu createCpu();

    /**
     * 創(chuàng)建主板
     * @return
     */
    public Mainboard createMainboard();

}

/**
 * 具體的工廠,amd產(chǎn)品族工廠
 */
public class AmdFactory implements AbstractFactory {
    @Override
    public Cpu createCpu() {
        return new AmdCpu();
    }

    @Override
    public Mainboard createMainboard() {
        return new AmdMainboard();
    }
}


/**
 * 具體的工廠秉馏,intel產(chǎn)品族工廠
 */
public class IntelFactory implements AbstractFactory {
    @Override
    public Cpu createCpu() {
        return new IntelCpu();
    }

    @Override
    public Mainboard createMainboard() {
        return new IntelMainboard();
    }
}
/**
 * 客戶端
 */
public class Client {

    public static void main(String[] args) {
        //amd工廠耙旦,若要生產(chǎn)intel的產(chǎn)品,只需在new 工廠時改為 new intelFactory即可
        AbstractFactory factory = new AmdFactory();
        Cpu cpu = factory.createCpu();
        Mainboard mainboard = factory.createMainboard();
        cpu.showMsg();
        mainboard.showMsg();
    }

}

抽象工廠的功能是為一系列相關(guān)對象或相互依賴的對象創(chuàng)建一個接口萝究。一定要注意免都,這個接口內(nèi)的方法不是任意堆砌的,而是一系列相關(guān)或相互依賴的方法帆竹。比如上面例子中的主板和CPU琴昆,都是為了組裝一臺電腦的相關(guān)對象。不同的裝機方案馆揉,代表一種具體的電腦系列业舍。

    
由于抽象工廠定義的一系列對象通常是相關(guān)或相互依賴的,這些產(chǎn)品對象就構(gòu)成了一個產(chǎn)品族升酣,也就是抽象工廠定義了一個產(chǎn)品族舷暮。
這就帶來非常大的靈活性,切換產(chǎn)品族的時候噩茄,只要提供不同的抽象工廠實現(xiàn)就可以了下面,也就是說現(xiàn)在是以一個產(chǎn)品族作為一個整體被切換。

在什么情況下應(yīng)當(dāng)使用抽象工廠模式
  1.一個系統(tǒng)不應(yīng)當(dāng)依賴于產(chǎn)品類實例如何被創(chuàng)建绩聘、組合和表達(dá)的細(xì)節(jié)沥割,這對于所有形態(tài)的工廠模式都是重要的。
  2.這個系統(tǒng)的產(chǎn)品有多于一個的產(chǎn)品族凿菩,而系統(tǒng)只消費其中某一族的產(chǎn)品机杜。
  3.同屬于同一個產(chǎn)品族的產(chǎn)品是在一起使用的,這一約束必須在系統(tǒng)的設(shè)計中體現(xiàn)出來衅谷。(比如:Intel主板必須使用Intel CPU、Intel芯片組)****
  4.系統(tǒng)提供一個產(chǎn)品類的庫蚀苛,所有的產(chǎn)品以同樣的接口出現(xiàn)在验,從而使客戶端不依賴于實現(xiàn)腋舌。

抽象工廠模式的起源

抽象工廠模式的起源或者最早的應(yīng)用块饺,是用于創(chuàng)建分屬于不同操作系統(tǒng)的視窗構(gòu)建拙徽。比如:命令按鍵(Button)與文字框(Text)都是視窗構(gòu)建膘怕,在UNIX操作系統(tǒng)的視窗環(huán)境和Windows操作系統(tǒng)的視窗環(huán)境中岛心,這兩個構(gòu)建有不同的本地實現(xiàn)篮灼,它們的細(xì)節(jié)有所不同诅诱。
  在每一個操作系統(tǒng)中娘荡,都有一個視窗構(gòu)建組成的構(gòu)建家族。在這里就是Button和Text組成的產(chǎn)品族争群。而每一個視窗構(gòu)件都構(gòu)成自己的等級結(jié)構(gòu)换薄,由一個抽象角色給出抽象的功能描述轻要,而由具體子類給出不同操作系統(tǒng)下的具體實現(xiàn)垦缅。


 
 
可以發(fā)現(xiàn)在上面的產(chǎn)品類圖中柏蘑,有兩個產(chǎn)品的等級結(jié)構(gòu),分別是Button等級結(jié)構(gòu)和Text等級結(jié)構(gòu)洽损。同時有兩個產(chǎn)品族革半,也就是UNIX產(chǎn)品族和Windows產(chǎn)品族又官。UNIX產(chǎn)品族由UNIX Button和UNIX Text產(chǎn)品構(gòu)成六敬;而Windows產(chǎn)品族由Windows Button和Windows Text產(chǎn)品構(gòu)成。


系統(tǒng)對產(chǎn)品對象的創(chuàng)建需求由一個工程的等級結(jié)構(gòu)滿足普泡,其中有兩個具體工程角色撼班,即UnixFactory和WindowsFactory砰嘁。UnixFactory對象負(fù)責(zé)創(chuàng)建Unix產(chǎn)品族中的產(chǎn)品矮湘,而WindowsFactory對象負(fù)責(zé)創(chuàng)建Windows產(chǎn)品族中的產(chǎn)品板祝。這就是抽象工廠模式的應(yīng)用走净,抽象工廠模式的解決方案如下圖:


顯然橘洞,一個系統(tǒng)只能夠在某一個操作系統(tǒng)的視窗環(huán)境下運行说搅,而不能同時在不同的操作系統(tǒng)上運行。所以适肠,系統(tǒng)實際上只能消費屬于同一個產(chǎn)品族的產(chǎn)品侯养。

在現(xiàn)代的應(yīng)用中,抽象工廠模式的使用范圍已經(jīng)大大擴大了柠傍,不再要求系統(tǒng)只能消費某一個產(chǎn)品族了惧笛。因此患整,可以不必理會前面所提到的原始用意并级。

抽象工廠模式的優(yōu)點

分離接口和實現(xiàn)
  客戶端使用抽象工廠來創(chuàng)建需要的對象,而客戶端根本就不知道具體的實現(xiàn)是誰稻励,客戶端只是面向產(chǎn)品的接口編程而已望抽。也就是說煤篙,客戶端從具體的產(chǎn)品實現(xiàn)中解耦。
使切換產(chǎn)品族變得容易
  因為一個具體的工廠實現(xiàn)代表的是一個產(chǎn)品族苛茂,比如上面例子的從Intel系列到AMD系列只需要切換一下具體工廠妓羊。

抽象工廠模式的缺點

不太容易擴展新的產(chǎn)品
  如果需要給整個產(chǎn)品族添加一個新的產(chǎn)品,那么就需要修改抽象工廠,這樣就會導(dǎo)致修改所有的工廠實現(xiàn)類剥哑。

抽象工廠和工廠方法的區(qū)別

抽象工廠模式與工廠方法模式的最大區(qū)別就在于星持,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu)督暂;而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)逻翁。

在什么情況下應(yīng)當(dāng)使用抽象工廠模式:
這個系統(tǒng)的產(chǎn)品有多于一個的產(chǎn)品族捡鱼,而系統(tǒng)只消費其中某一族的產(chǎn)品驾诈。比如XX應(yīng)用系統(tǒng)有快捷版跟標(biāo)準(zhǔn)版兩個版本管引,這就是兩個產(chǎn)品族褥伴,而具體使用哪一個產(chǎn)品族是實施人員在部署的時候設(shè)置后臺參數(shù)來決定的漾狼。

同屬于同一個產(chǎn)品族的產(chǎn)品是在一起使用的似踱,這一約束必須在系統(tǒng)的設(shè)計中體現(xiàn)出來稽煤。比如:快捷版數(shù)據(jù)保存在XML文件中狞洋,而標(biāo)準(zhǔn)版數(shù)據(jù)保存在數(shù)據(jù)庫中吉懊。將UserDAO和DeptDAO看作是這兩個版本(產(chǎn)品族)擁有的產(chǎn)品借嗽,而抽象工廠有兩個具體工廠實現(xiàn)類ShortcutFactory浆竭、StandardFactory負(fù)責(zé)分別創(chuàng)建快捷版ShortcutUserDAO惨寿、ShortcutDeptDAO和標(biāo)準(zhǔn)版StandardUserDAO顺囊、StandardDeptDAO。當(dāng)用戶操作刪除一個部門的時候蕉拢,先需要刪除這個部門下的所有用戶特碳。假如不使用抽象工廠可能會出現(xiàn)如下情況:后臺刪除用戶時調(diào)用的是快捷版的ShortcutUserDAO類,刪除部門時調(diào)用的是StandardDeptDAO類晕换。這樣就會出現(xiàn)問題午乓。
如果使用抽象工廠,那抽象工廠的具體實現(xiàn)類會幫你創(chuàng)建一個產(chǎn)品族中的一系列產(chǎn)品對象闸准,如標(biāo)準(zhǔn)版的StandardFactory工廠會創(chuàng)建StandardUserDAO益愈、StandardDeptDAO,快捷版的ShortcutFactory工廠會創(chuàng)建ShortcutUserDAO恕汇、ShortcutDeptDAO腕唧。
其實抽象工廠就是起到了一定的約束作用或辖,它所創(chuàng)建的都是同一個產(chǎn)品族中的一系列產(chǎn)品對象颂暇。防止出現(xiàn)上面例子中創(chuàng)建不同產(chǎn)品族中產(chǎn)品所帶來的問題。

總結(jié)

無論是簡單工廠模式,工廠方法模式察迟,還是抽象工廠模式,他們都屬于工廠模式,在形式和特點上也是極為相似的继薛,他們的最終目的都是為了解耦诈皿。在使用時缕题,我們不必去在意這個模式到底工廠方法模式還是抽象工廠模式,因為他們之間的演變常常是令人琢磨不透的。經(jīng)常你會發(fā)現(xiàn),明明使用的工廠方法模式,當(dāng)新需求來臨,稍加修改寡润,加入了一個新方法后,由于類中的產(chǎn)品構(gòu)成了不同等級結(jié)構(gòu)中的產(chǎn)品族,它就變成抽象工廠模式了;而對于抽象工廠模式僚焦,當(dāng)減少一個方法使的提供的產(chǎn)品不再構(gòu)成產(chǎn)品族之后名扛,它就演變成了工廠方法模式旺订。
所以,在使用工廠模式時本涕,只需要關(guān)心降低耦合度的目的是否達(dá)到了晦闰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眉撵,一起剝皮案震驚了整個濱河市污朽,隨后出現(xiàn)的幾起案子颓芭,更是在濱河造成了極大的恐慌州藕,老刑警劉巖锈死,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蛤袒,居然都是意外死亡,警方通過查閱死者的電腦和手機膨更,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門健蕊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缩功,“玉大人,你說我怎么就攤上這事啦桌∮瞩耍” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疯淫。 經(jīng)常有香客問我地来,道長,這世上最難降的妖魔是什么熙掺? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任未斑,我火速辦了婚禮,結(jié)果婚禮上币绩,老公的妹妹穿的比我還像新娘蜡秽。我一直安慰自己,他們只是感情好缆镣,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布芽突。 她就那樣靜靜地躺著,像睡著了一般董瞻。 火紅的嫁衣襯著肌膚如雪寞蚌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天钠糊,我揣著相機與錄音挟秤,去河邊找鬼。 笑死眠蚂,一個胖子當(dāng)著我的面吹牛煞聪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逝慧,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼昔脯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笛臣?” 一聲冷哼從身側(cè)響起云稚,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沈堡,沒想到半個月后静陈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年鲸拥,在試婚紗的時候發(fā)現(xiàn)自己被綠了拐格。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡刑赶,死狀恐怖捏浊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撞叨,我是刑警寧澤金踪,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站牵敷,受9級特大地震影響胡岔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜枷餐,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一靶瘸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尖淘,春花似錦奕锌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趁桃,卻和暖如春辽话,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卫病。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工油啤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蟀苛。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓益咬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帜平。 傳聞我的和親對象是個殘疾皇子幽告,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

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

  • 工廠方法模式通過引入工廠等級結(jié)構(gòu),解決了簡單工廠模式中工廠類職責(zé)太重的問題裆甩,但由于工廠方法模式中的每個工廠只生產(chǎn)一...
    justCode_閱讀 1,203評論 1 6
  • 設(shè)計原則: 要依賴抽象冗锁,不要依賴具體類 目錄 本文的結(jié)構(gòu)如下: 什么是抽象工廠模式 為什么要用該模式 模式的結(jié)構(gòu) ...
    w1992wishes閱讀 1,118評論 0 6
  • 簡單工廠模式 工廠模式我的理解是:他就是為了創(chuàng)建對象的 創(chuàng)建對象的時候,我們一般是alloc一個對象嗤栓,如果需要創(chuàng)建...
    GitHubPorter閱讀 8,071評論 6 16
  • 設(shè)計模式匯總 一冻河、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用箍邮、多...
    MinoyJet閱讀 3,949評論 1 15
  • 想贏?堅持叨叙?主動锭弊? 想贏嗎?是的摔敛,我想贏廷蓉,想了已經(jīng)不止n次了全封,已經(jīng)到n+n+n+n……次了马昙。 可以光想有用嗎?好像...
    肖輝閱讀 191評論 0 0