詳解Java設(shè)計模式之《工廠方法模式》

上一篇介紹簡單工廠模式 的時候提到它對開閉原則 支持的不夠,因為如果有新的產(chǎn)品加入到系統(tǒng)中去繁疤,就需要修改工廠類,就違反了開閉原則 了躁染,這次介紹的工廠方法模式在保持簡單工廠模式優(yōu)點的前提下架忌,不僅滿足了開閉原則,關(guān)鍵在于它的多態(tài)性饰恕。

開閉原則(Open Close Principle):就是說**對擴展開放井仰,對修改關(guān)閉 ** 。在程序需要進行擴展的時候雹嗦,不能去修改原有的代碼合是,而是要擴展原有的代碼,實現(xiàn)一個熱插拔的效果泊藕。為了使程序的擴展性好难礼,易于維護和升級。想要達到這樣的效果蛾茉,我們需要使用接口和抽象類等。

概念

工廠方法模式(Factory Method Pattern):定義一個用于創(chuàng)建對象的接口吝岭,讓子類決定將哪一個類實例化吧寺。工廠方法模式讓一個類的實例化延遲到其子類稚机。工廠方法模式又簡稱工廠模式(Factory Pattern),有可稱作虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)赖条。工廠方法模式是一種類創(chuàng)建型模式。

作用

在工廠方法模式中碱茁,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的產(chǎn)品對象,而是針對不同的產(chǎn)品提供不同的工廠墓贿,系統(tǒng)提供一個與產(chǎn)品等級結(jié)構(gòu)對應(yīng)的工廠等級結(jié)構(gòu)蜓氨。

實現(xiàn)方式

工廠方法模式的結(jié)構(gòu)圖如下:

從上圖可以看出穴吹,工廠方法模式涉及到抽象工廠角色、具體工廠角色港令、抽象產(chǎn)品角色以及具體產(chǎn)品角色等四個角色:

  • 抽象工廠角色:擔任這個角色是工廠方法模式的核心,它是與應(yīng)用程序無關(guān)的缠借。任何在模式中創(chuàng)建對象的工廠類必須實現(xiàn)這個接口泼返。
  • 具體工廠角色:擔任這個角色的是實現(xiàn)了抽象工廠接口的具體Java類姨拥,具體工廠角色含有與應(yīng)用密切相關(guān)的邏輯,并且受到應(yīng)用程序的調(diào)用以創(chuàng)建產(chǎn)品對象柴罐。
  • 抽象產(chǎn)品角色:工廠方法模式所創(chuàng)建的對象的超類型憨奸,也就是產(chǎn)品對象的共同父類或共同擁有的接口。
  • 具體產(chǎn)品角色:這個角色實現(xiàn)了抽象產(chǎn)品角色所申明的接口似芝。工廠方法模式所創(chuàng)建的每一個對象都是某個具體產(chǎn)品角色的實例板甘。

結(jié)合披薩系統(tǒng),就是之前廚師(工廠類)負責所有的烤披薩任務(wù)寞奸,太累了。于是招了兩個廚師分別負責烤GreekPizza 披薩和ChesePizza 披薩枪萄,之前的廚師升級為廚師長(抽象工廠類)瓷翻,負責教那兩位廚師(具體工廠類)烤披薩,自己則不用親自動手烤披薩了逻悠。

附上完整的類圖:

下面是抽象產(chǎn)品的角色Pizza的源代碼:

public abstract class Pizza{
    public abstract void prepare();
    public abstract void bake();
    public abstract void cut();
}

下面是具體角色CheesePizza的源代碼:

public class CheesePizza extends Pizza{
    public void prepare(){
        System.out.pringln("準備CheesePizza");
    }
    public void bake(){
        System.out.pringln("準備CheesePizza");
    }
    public void cut(){
        System.out.pringln("準備CheesePizza");
    }
    public void box(){
        System.out.pringln("準備CheesePizza");
    }
}

下面是具體角色GreekPizza的源代碼:

public class GreekPizza extends Pizza{
    public void prepare(){
        System.out.pringln("準備GreekPizza");
    }
    public void bake(){
        System.out.pringln("準備GreekPizza");
    }
    public void cut(){
        System.out.pringln("準備GreekPizza");
    }
    public void box(){
        System.out.pringln("準備GreekPizza");
    }
}

下面是抽象工廠角色PizzaFactory的代碼单旁,這個角色是使用一個Java接口實現(xiàn)饥伊,它聲明了一個工廠方法,要求所有的具體工廠角色實現(xiàn)這個工廠方法:

public interface PizzaFactory{
    //工廠方法
    public Pizza createPizza();
}

下面是具體工廠角色CheesePizzaFactory的代碼愉豺,這個角色實現(xiàn)了抽象工廠角色PizzaFactory所聲明的工廠方法:

public class CheesePizzaFactory implements PizzaFactory{
    @Override
    public Pizza createPizza(){
        return new CheesePizza();
    }
}

下面是具體工廠角色GreekPizzaFactory的代碼茫因,這個角色實現(xiàn)了抽象工廠角色PizzaFactory所聲明的工廠方法:

public class GreekPizzaFactory implements PizzaFactory{
    @Override
    public Pizza createPizza(){
        return new GreekPizza();
    }
}

下面是客戶端角色的源代碼:

public class OrderPizaa{
    public static void main(String[] args){
        //創(chuàng)建CheesePizzaFactory--具體工廠類
        //可以通過反射和配置文件來獲取和存儲具體工廠類的類名冻押,更換新的具體工廠時無須修改源代碼,系統(tǒng)擴展更為方便
        PizzaFactory factory = new CheesePizzaFactory();
        Pizza pizza = factory.createPizza();
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        //創(chuàng)建GreekPizzaFactory()--具體工廠類
        pizza = factory.createPizza();
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
    }
}

結(jié)果演示:

準備CheesePizza
正在烤CheesePizza
正在切CheesePizza
正在打包CheesePizza
準備GreekPizza
正在烤GreekPizza
正在切GreekPizza
正在打包GreekPizza

這里使用工廠方法模式的要點:

工廠方法創(chuàng)建對象

  • 工廠方法不一定每一次都返回一個新的對象括袒,但是它所返回的對象一定是它自己創(chuàng)建 的稿茉。

工廠方法返回的類型

  • 注意:工廠方法返回的應(yīng)當是抽象類型 ,而不是具體類型恃慧,只有這樣才能保證針對產(chǎn)品的多態(tài)性米苹。

工廠等級結(jié)構(gòu)

  • 工廠對象應(yīng)當有一個抽象的超類型。就是說良瞧,應(yīng)當有數(shù)個具體工廠類作為一個抽象超類型的具體子類存在于工廠等級結(jié)構(gòu)中。如果等級結(jié)構(gòu)中只有一個具體工廠類的話褥蚯,那么抽象工廠角色也可以省略赞庶,這時候,工廠方法模式就發(fā)生了退化歧强,這一退化表現(xiàn)為針對工廠角色的多態(tài)性的喪失摊册。

工廠方法模式的優(yōu)缺點

優(yōu)點:

  • 工廠方法模式跟簡單工廠模式在結(jié)構(gòu)上不同是很明顯的,工廠方法模式的核心是一個抽象工廠類茅特,而簡單工廠模式的核心在一個具體類。顯而易見妒峦,工廠方法模式這種結(jié)構(gòu)更好擴展兵睛。
  • 如果系統(tǒng)需要加入一個新的產(chǎn)品,那么所需要的就是想系統(tǒng)中加入這個產(chǎn)品類以及它所對應(yīng)的工廠類累盗,沒有必要修改客戶端突琳,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色符相。對于增加新的產(chǎn)品類而言,這個系統(tǒng)完全支持開閉原則镜豹。

應(yīng)用場景

不管是簡單工廠模式蓝牲,工廠方法模式還是抽象工廠模式,他們具有類似的特性例衍,所以他們的適用場景也是類似的已卸。

? 首先累澡,作為一種創(chuàng)建類模式般贼,在任何需要生成復(fù)雜對象的地方,都可以使用工廠方法模式哼蛆。有一點需要注意的地方就是復(fù)雜對象適合使用工廠模式腮介,而簡單對象,特別是只需要通過new就可以完成創(chuàng)建的對象萤厅,無需使用工廠模式惕味。如果使用工廠模式,就需要引入一個工廠類名挥,會增加系統(tǒng)的復(fù)雜度禀倔。

? 其次,工廠模式是一種典型的解耦模式救湖,迪米特法則在工廠模式中表現(xiàn)的尤為明顯鞋既。假如調(diào)用者自己組裝產(chǎn)品需要增加依賴關(guān)系時,可以考慮使用工廠模式邑闺。將會大大降低對象之間的耦合度陡舅。

? 再次,由于工廠模式是依靠抽象架構(gòu)的灾炭,它把實例化產(chǎn)品的任務(wù)交由實現(xiàn)類完成,擴展性比較好咆贬。也就是說,當需要系統(tǒng)有比較好的擴展性時皱蹦,可以考慮工廠模式眷蜈,不同的產(chǎn)品用不同的實現(xiàn)工廠來組裝酌儒。

迪米特法則(Law of Demeter):一個軟件實體應(yīng)當盡可能少地與其他實體發(fā)生相互作用。

在將迪米特法則運用到系統(tǒng)設(shè)計中時忌怎,要注意下面的幾點:

  • 在類的劃分中榴啸,應(yīng)當盡量創(chuàng)建松耦合的類,類之間的耦合度越低鸥印,就月有利于復(fù)用库说,一個處在松耦合的類一旦被修改,不會對關(guān)聯(lián)的類造成太大的波及潜的。
  • 在類的結(jié)構(gòu)設(shè)計上夏块,每一個類都應(yīng)當盡量降低其成員變量和成員函數(shù)的訪問權(quán)限。
  • 在類的設(shè)計上,只要有可能借跪,一個類型應(yīng)當設(shè)計成不變類。
  • 在對其他類的引用上歇由,一個對象對其他對象的引用應(yīng)當降到最低。

參考資料

嘟嘟獨立博客
劉偉

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糊昙,一起剝皮案震驚了整個濱河市释牺,隨后出現(xiàn)的幾起案子回挽,更是在濱河造成了極大的恐慌,老刑警劉巖祭刚,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涡驮,死亡現(xiàn)場離奇詭異喜滨,居然都是意外死亡,警方通過查閱死者的電腦和手機鸿市,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門焰情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人合敦,你說我怎么就攤上這事验游。” “怎么了佛嬉?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵垒在,是天一觀的道長。 經(jīng)常有香客問我,道長旅挤,這世上最難降的妖魔是什么伞鲫? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任秕脓,我火速辦了婚禮,結(jié)果婚禮上嘹朗,老公的妹妹穿的比我還像新娘诵肛。我一直安慰自己,他們只是感情好怔檩,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布薛训。 她就那樣靜靜地躺著,像睡著了一般闸英。 火紅的嫁衣襯著肌膚如雪介袜。 梳的紋絲不亂的頭發(fā)上遇伞,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音巍耗,去河邊找鬼渐排。 笑死,一個胖子當著我的面吹牛娄琉,可吹牛的內(nèi)容都是我干的吓歇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼女气,長吁一口氣:“原來是場噩夢啊……” “哼测柠!你這毒婦竟也來了轰胁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤霎肯,失蹤者是張志新(化名)和其女友劉穎榛斯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懂缕,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡搪柑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年索烹,在試婚紗的時候發(fā)現(xiàn)自己被綠了术荤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡端圈,死狀恐怖子库,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宴倍,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布俗他,位于F島的核電站阔逼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏羡亩。R本人自食惡果不足惜危融,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一吉殃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧速侈,春花似錦迫卢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趴樱,卻和暖如春酪捡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逛薇。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工永罚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卧秘,地道東北人官扣。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓醇锚,卻偏偏與公主長得像坯临,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赶促,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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

  • 設(shè)計模式匯總 一鸥滨、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用谤祖、多...
    MinoyJet閱讀 3,939評論 1 15
  • 簡單工廠模式雖然簡單婿滓,但存在一個很嚴重的問題。當系統(tǒng)中需要引入新產(chǎn)品時粥喜,由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建...
    justCode_閱讀 1,184評論 1 9
  • 簡單工廠模式是工廠模式中家族最簡單實用的模式凸主,可以理解為不同工廠模式的一個特殊的實現(xiàn)。 值得注意的是:簡單工廠模式...
    Michaelhbjian閱讀 1,221評論 0 1
  • 你給這本書打幾顆星额湘? 答:五顆星卿吐!原因:這本書打開了我的金錢觀,讓我認識到锋华,如果我想成為富人嗡官,首先我要有富人思維。...
    小米粥毛毛閱讀 2,245評論 4 3
  • 參考1 kurento Android Get a media stream Stream between pee...
    heiheiwanne閱讀 1,337評論 0 0