工廠模式--工廠方法模式

設(shè)計模式
設(shè)計原則:
要依賴抽象逗载,不要依賴具體類

簡單工廠模式雖然簡單哆窿,但存在一個很嚴重的問題。當(dāng)系統(tǒng)中需要引入新產(chǎn)品時厉斟,由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建不同的產(chǎn)品挚躯,這必定要修改工廠類的源代碼,將違背“開閉原則”擦秽,如何實現(xiàn)增加新產(chǎn)品而不影響已有代碼码荔?工廠方法模式應(yīng)運而生,本文將介紹第二種工廠模式——工廠方法模式感挥。

1 什么是工廠方法模式

工廠方法模式(Factory Method Pattern)又稱為工廠模式缩搅,也叫虛擬構(gòu)造器(Virtual Constructor)模式或者多態(tài)工廠(Polymorphic Factory)模式,它屬于類創(chuàng)建型模式触幼。

在工廠方法模式中硼瓣,工廠父類負責(zé)定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類則負責(zé)生成具體的產(chǎn)品對象置谦,這樣做的目的是將產(chǎn)品類的實例化操作延遲到工廠子類中完成堂鲤,即通過工廠子類來確定究竟應(yīng)該實例化哪一個具體產(chǎn)品類亿傅。

2 為什么要用該模式

在簡單工廠模式中只提供一個工廠類,該工廠類處于對產(chǎn)品類進行實例化的中心位置瘟栖,它需要知道每一個產(chǎn)品對象的創(chuàng)建細節(jié)葵擎,并決定何時實例化哪一個產(chǎn)品類。簡單工廠模式最大的缺點是當(dāng)有新產(chǎn)品要加入到系統(tǒng)中時慢宗,必須修改工廠類坪蚁,需要在其中加入必要的業(yè)務(wù)邏輯,這違背了“開閉原則”镜沽。

此外敏晤,在簡單工廠模式中,所有的產(chǎn)品都由同一個工廠創(chuàng)建缅茉,工廠類職責(zé)較重嘴脾,業(yè)務(wù)邏輯較為復(fù)雜,具體產(chǎn)品與工廠類之間的耦合度高蔬墩,嚴重影響了系統(tǒng)的靈活性和擴展性译打,而工廠方法模式則可以很好地解決這一問題。

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

3 模式的結(jié)構(gòu)

7017386-4a72e4cf30c1f0c6.png

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

  • Factory(抽象工廠類):在抽象工廠類中韵洋,聲明了工廠方法(Factory Method),用于返回一個產(chǎn)品黄锤。抽象工廠是工廠方法模式的核心搪缨,所有創(chuàng)建對象的工廠類都必須實現(xiàn)該接口。

  • ConcreteFactory(具體工廠類):它是抽象工廠類的子類鸵熟,實現(xiàn)了抽象工廠中定義的工廠方法副编,并可由客戶端調(diào)用,返回一個具體產(chǎn)品類的實例流强。

  • Product(抽象產(chǎn)品類):它是定義產(chǎn)品的接口痹届,是工廠方法模式所創(chuàng)建對象的超類型,也就是產(chǎn)品對象的公共父類打月。

  • (ConcreteProduct具體產(chǎn)品類):它實現(xiàn)了抽象產(chǎn)品接口短纵,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建,具體工廠和具體產(chǎn)品之間一一對應(yīng)僵控。

與簡單工廠模式相比,工廠方法模式最重要的區(qū)別是引入了抽象工廠角色鱼冀,抽象工廠可以是接口报破,也可以是抽象類或者具體類悠就。

4 代碼示例

4.1 抽象產(chǎn)品

/**
 * Created by w1992wishes on 2017/11/01.
 */
public abstract class Cake {
    void prepare(){
        System.out.println("step 1......");
        System.out.println("step 2......");
        System.out.println("step 3......");
        System.out.println("step 4......");
    }
    void bake(){
        System.out.println("bake");
    }
    void box(){
        System.out.println("box");
    }
}

4.2 具體產(chǎn)品

* Created by w1992wishes on 2017/10/31.
 */
public class CenterCheeseCake extends Cake {
    public CenterCheeseCake(){
        name = "center cheese cake";
    }
    @Override
    public void bake(){
        System.out.println("不用烘箱,我要用火烤充易!");
    }
}
/**
 * Created by w1992wishes on 2017/11/1.
 */
public class CollegeFruitCake extends Cake {
    public CollegeFruitCake(){
        name = "center fruit cake";
    }
    @Override
    public void box(){
        System.out.println("不用圓盒子打包梗脾,我愛國,用五角星盒子盹靴!");
    }
}

4.3 抽象工廠

首先定義一個抽象工廠炸茧,這個抽象工廠有一個抽象方法用于生產(chǎn)具體產(chǎn)品:

/**
 * Created by w1992wishes on 2017/11/01.
 */
public abstract class CakeStore {
    public Cake orderCake(String type) {
        Cake cake;
        cake = createCake(type);
        cake.bake();
        cake.box();
        return cake;
    }

    protected abstract Cake createCake(String type);
}

4.4 具體工廠類

在抽象工廠中聲明了工廠方法但并未實現(xiàn)工廠方法,具體產(chǎn)品對象的創(chuàng)建由其子類負責(zé)稿静,客戶端針對抽象工廠編程梭冠,可在運行時再指定具體工廠類,具體工廠類實現(xiàn)了工廠方法改备,不同的具體工廠可以創(chuàng)建不同的具體產(chǎn)品控漠。

/**
 * Created by w1992wishes on 2017/11/1.
 */
public class CenterCakeStore extends CakeStore {
    @Override
    protected Cake createCake(String type) {
        Cake cake = null;
        if ("cheese".equals(type)) {
            cake = new CenterCheeseCake();
        } else if ("fruit".equals(type)) {
            cake = new CenterFruitCake();
        } else if ("cream".equals(type)) {
            cake = new CenterCreamCake();
        }
        return cake;
    }
}
/**
 * Created by w1992wishes on 2017/11/1.
 */
public class CollegeCakeStore extends CakeStore {
    @Override
    protected Cake createCake(String type) {
        Cake cake = null;
        if ("cheese".equals(type)) {
            cake = new CollegeCheeseCake();
        } else if ("fruit".equals(type)) {
            cake = new CollegeFruitCake();
        } else if ("cream".equals(type)) {
            cake = new CollegeCreamCake();
        }
        return cake;
    }
}

5 優(yōu)點和缺點

5.1 優(yōu)點

  • 在工廠方法模式中,工廠方法用來創(chuàng)建客戶端所需要的產(chǎn)品悬钳,同時還向客戶端隱藏了哪種具體產(chǎn)品類將被實例化這一細節(jié)盐捷,客戶端只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠,無須關(guān)心創(chuàng)建細節(jié)默勾,甚至無須知道具體產(chǎn)品類的類名碉渡。

  • 基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計是工廠方法模式的關(guān)鍵。它能夠使工廠可以自主確定創(chuàng)建何種產(chǎn)品對象母剥,而如何創(chuàng)建這個對象的細節(jié)則完全封裝在具體工廠內(nèi)部滞诺。工廠方法模式之所以又被稱為多態(tài)工廠模式,是因為所有的具體工廠類都具有同一抽象父類媳搪。

  • 使用工廠方法模式的另一個優(yōu)點是在系統(tǒng)中加入新產(chǎn)品時铭段,無須修改抽象工廠和抽象產(chǎn)品提供的接口,無須修改客戶端秦爆,也無須修改其他的具體工廠和具體產(chǎn)品序愚,而只要添加一個具體工廠和具體產(chǎn)品就可以了。這樣等限,系統(tǒng)的可擴展性也就變得非常好爸吮,完全符合“開閉原則”。

5.2 缺點

  • 在添加新產(chǎn)品時望门,需要編寫新的具體產(chǎn)品類形娇,而且還要提供與之對應(yīng)的具體工廠類,系統(tǒng)中類的個數(shù)將成對增加筹误,在一定程度上增加了系統(tǒng)的復(fù)雜度桐早,有更多的類需要編譯和運行,會給系統(tǒng)帶來一些額外的開銷
  • 由于考慮到系統(tǒng)的可擴展性哄酝,需要引入抽象層友存,在客戶端代碼中均使用抽象層進行定義,增加了系統(tǒng)的抽象性和理解難度陶衅,且在實現(xiàn)時可能需要用到DOM屡立、反射等技術(shù),增加了系統(tǒng)的實現(xiàn)難度搀军。

工廠方法模式比起簡單工廠模式更加符合開閉原則膨俐。

工廠模式需要額外創(chuàng)建諸多 Factory 類,也會增加代碼的復(fù)雜性罩句,而且焚刺,每個 Factory 類只是做簡單的 new 操作,功能非常單钡闹埂(只有一行代碼)檩坚,也沒必要設(shè)計成獨立的類,所以诅福,在這個應(yīng)用場景下匾委,簡單工廠模式簡單好用,比工廠方法模式更加合適氓润。

6 適用環(huán)境

  • 一個類不知道它所需要的對象的類:在工廠方法模式中赂乐,客戶端不需要知道具體產(chǎn)品類的類名,只需要知道所對應(yīng)的工廠即可咖气,具體的產(chǎn)品對象由具體工廠類創(chuàng)建挨措;客戶端需要知道創(chuàng)建具體產(chǎn)品的工廠類
  • 一個類通過其子類來指定創(chuàng)建哪個對象:在工廠方法模式中崩溪,對于抽象工廠類只需要提供一個創(chuàng)建產(chǎn)品的接口浅役,而由其子類來確定具體要創(chuàng)建的對象,利用面向?qū)ο蟮亩鄳B(tài)性和里氏代換原則伶唯,在程序運行時觉既,子類對象將覆蓋父類對象,從而使得系統(tǒng)更容易擴展乳幸。
  • 將創(chuàng)建對象的任務(wù)委托給多個工廠子類中的某一個瞪讼,客戶端在使用時可以無須關(guān)心是哪一個工廠子類創(chuàng)建產(chǎn)品子類,需要時再動態(tài)指定粹断,可將具體工廠類的類名存儲在配置文件或數(shù)據(jù)庫中符欠。

7 模式擴展

  • 使用多個工廠方法:在抽象工廠角色中可以定義多個工廠方法,從而使具體工廠角色實現(xiàn)這些不同的工廠方法瓶埋,這些方法可以包含不同的業(yè)務(wù)邏輯希柿,以滿足對不同的產(chǎn)品對象的需求诊沪。
  • 產(chǎn)品對象的重復(fù)使用:工廠對象將已經(jīng)創(chuàng)建過的產(chǎn)品保存到一個集合(如數(shù)組、List等)中狡汉,然后根據(jù)客戶對產(chǎn)品的請求娄徊,對集合進行查詢。如果有滿足要求的產(chǎn)品對象盾戴,就直接將該產(chǎn)品返回客戶端;如果集合中沒有這樣的產(chǎn)品對象兵多,那么就創(chuàng)建一個新的滿足要求的產(chǎn)品對象尖啡,然后將這個對象在增加到集合中,再返回給客戶端剩膘。
  • 多態(tài)性的喪失和模式的退化:如果工廠僅僅返回一個具體產(chǎn)品對象衅斩,便違背了工廠方法的用意,發(fā)生退化怠褐,此時就不再是工廠方法模式了畏梆。一般來說,工廠對象應(yīng)當(dāng)有一個抽象的父類型奈懒,如果工廠等級結(jié)構(gòu)中只有一個具體工廠類的話奠涌,抽象工廠就可以省略,也將發(fā)生了退化磷杏。當(dāng)只有一個具體工廠溜畅,在具體工廠中可以創(chuàng)建所有的產(chǎn)品對象,并且工廠方法設(shè)計為靜態(tài)方法時极祸,工廠方法模式就退化成簡單工廠模式慈格。

之所以將某個代碼塊剝離出來,獨立為函數(shù)或者類遥金,原因是這個代碼塊的邏輯過于復(fù)雜浴捆,剝離之后能讓代碼更加清晰,更加可讀稿械、可維護选泻。

基于這個設(shè)計思想,當(dāng)對象的創(chuàng)建邏輯比較復(fù)雜溜哮,不只是簡單的 new 一下就可以滔金,而是要組合其他類對象,做各種初始化操作的時候茂嗓,我們推薦使用工廠方法模式餐茵,將復(fù)雜的創(chuàng)建邏輯拆分到多個工廠類中,讓每個工廠類都不至于過于復(fù)雜述吸。
而使用簡單工廠模式忿族,將所有的創(chuàng)建邏輯都放到一個工廠類中锣笨,會導(dǎo)致這個工廠類變得很復(fù)雜。

參考

設(shè)計模式--工廠方法模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末道批,一起剝皮案震驚了整個濱河市错英,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隆豹,老刑警劉巖椭岩,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異璃赡,居然都是意外死亡判哥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進店門碉考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塌计,“玉大人,你說我怎么就攤上這事侯谁⌒拷觯” “怎么了?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵墙贱,是天一觀的道長热芹。 經(jīng)常有香客問我,道長嫩痰,這世上最難降的妖魔是什么剿吻? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮串纺,結(jié)果婚禮上丽旅,老公的妹妹穿的比我還像新娘。我一直安慰自己纺棺,他們只是感情好榄笙,可當(dāng)我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祷蝌,像睡著了一般茅撞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巨朦,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天米丘,我揣著相機與錄音,去河邊找鬼糊啡。 笑死拄查,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棚蓄。 我是一名探鬼主播堕扶,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼碍脏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了稍算?” 一聲冷哼從身側(cè)響起典尾,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糊探,沒想到半個月后钾埂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡科平,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年勃教,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匠抗。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖污抬,靈堂內(nèi)的尸體忽然破棺而出汞贸,到底是詐尸還是另有隱情,我是刑警寧澤印机,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布矢腻,位于F島的核電站,受9級特大地震影響射赛,放射性物質(zhì)發(fā)生泄漏多柑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一楣责、第九天 我趴在偏房一處隱蔽的房頂上張望竣灌。 院中可真熱鬧,春花似錦秆麸、人聲如沸初嘹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屯烦。三九已至,卻和暖如春房铭,著一層夾襖步出監(jiān)牢的瞬間驻龟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工缸匪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翁狐,地道東北人。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓豪嗽,卻偏偏與公主長得像谴蔑,于是被迫代替她去往敵國和親豌骏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,442評論 2 359

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