設(shè)計(jì)模式--簡(jiǎn)單工廠模式

設(shè)計(jì)原則:

要依賴抽象,不要依賴具體類

目錄

本文的結(jié)構(gòu)如下:

  • 什么是簡(jiǎn)單工廠模式
  • 為什么要該模式
  • 模式的結(jié)構(gòu)
  • 代碼示例
  • 優(yōu)點(diǎn)和缺點(diǎn)
  • 適用環(huán)境
  • 模式應(yīng)用
  • 總結(jié)

一由桌、前言

工廠模式是一個(gè)比較復(fù)雜的模式伶授,可以分為三類:

  • 簡(jiǎn)單工廠模式
  • 工廠方法模式
  • 抽象工廠模式

準(zhǔn)確說(shuō)贵少,簡(jiǎn)單工廠模式并不屬于GoF 23種設(shè)計(jì)模式组砚,但在軟件開發(fā)中應(yīng)用較為頻繁峻呕,通常將它作為學(xué)習(xí)其他工廠模式的入門利职。

二、什么是簡(jiǎn)單工廠模式

簡(jiǎn)單工廠模式(Simple Factory Pattern):又稱為靜態(tài)工廠方法(Static Factory Method)模式瘦癌,它屬于類創(chuàng)建型模式猪贪。在簡(jiǎn)單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例讯私。簡(jiǎn)單工廠模式專門定義一個(gè)類來(lái)負(fù)責(zé)創(chuàng)建其他類的實(shí)例热押,被創(chuàng)建的實(shí)例通常都具有共同的父類。

三斤寇、為什么要用該模式

假設(shè)你經(jīng)過(guò)深思熟慮桶癣,走到老板的辦公司,微笑著對(duì)老板說(shuō):“老板娘锁,我是來(lái)辦理離職的牙寞。”老板再三挽留莫秆,不舍放走你這個(gè)人才碎税,給你漲三倍薪資,你依然面不改色馏锡,毅然拒絕了雷蹂,因?yàn)槟阋呀?jīng)在市中心買下了一家店面,正準(zhǔn)備做自己的老板--賣蛋糕杯道。

辭職后匪煌,你找我寫訂蛋糕的相關(guān)代碼责蝠,(現(xiàn)在只有四種蛋糕,芝士蛋糕萎庭,水果蛋糕霜医,奶油蛋糕及默認(rèn)什么也不加的蛋糕),于是我這樣寫:

/**
 * Created by w1992wishes on 2017/10/31.
 */
public class CakeStore {
    public Cake orderCake(String type) {
        Cake cake;
        if ("cheese".equals(type)) {
            cake = new CheeseCake();
        } else if ("fruit".equals(type)) {
            cake = new FruitCake();
        } else if ("cream".equals(type)) {
            cake = new CreamCake();
        } else {
            cake = new DefaultCake();
        }
        cake.bake();
        cake.box();
        return cake;
    }
}

你新開的蛋糕店賣的很好驳规,想新增加一些品種肴敛,比如巧克力蛋糕,于是我需要這樣修改:

我把代碼修改后給了你吗购,出于負(fù)責(zé)的態(tài)度医男,你百忙中抽空看了一遍,你驚呆了,你說(shuō),“你就是一堆狗屎疑故,這種代碼都能寫出來(lái)?”报账。

你張大了嘴對(duì)我咆哮,口水噴了我一臉埠偿,但作為前程序猿透罢,你有著專業(yè)的精神,你壓著洶涌的怒火冠蒋,教導(dǎo)我說(shuō):

CakeStore類是一個(gè)“巨大的”類羽圃,在該類的設(shè)計(jì)中存在如下幾個(gè)問(wèn)題:

  1. 在CakeStore類orderCake()中包含很多“if…else…”代碼塊,代碼相當(dāng)冗長(zhǎng)浊服,代碼越長(zhǎng)统屈,閱讀難度胚吁、維護(hù)難度和測(cè)試難度也越大牙躺;而且大量條件語(yǔ)句的存在還將影響系統(tǒng)的性能,程序在執(zhí)行過(guò)程中需要做大量的條件判斷腕扶。
  2. CakeStore類orderCake()的職責(zé)過(guò)重孽拷,它負(fù)責(zé)初始化所有的蛋糕對(duì)象,并且還要進(jìn)行bake()和box()半抱,將各種蛋糕對(duì)象的初始化代碼和bake()脓恕、box()集中在一個(gè)方法中實(shí)現(xiàn),違反了“單一職責(zé)原則”窿侈,不利于方法的重用和維護(hù)炼幔。
  3. 當(dāng)需要增加新類型的蛋糕時(shí),必須修改CakeStore類的源代碼史简,違反了“開閉原則”乃秀。
  4. 如果新開一家蛋糕店,則必須重復(fù)寫一堆“if...else”代碼塊用來(lái)創(chuàng)建Cake對(duì)象,重新寫了一堆重復(fù)代碼跺讯。
  5. ......

憤怒的你把我辭退枢贿,掏出還裹著面粉的手,重操舊業(yè)刀脏,10分鐘局荚,不,只用了2分鐘愈污,你就改好了耀态。于是你拍了拍腦袋,懊惱說(shuō):“我當(dāng)時(shí)為什么要找那堆狗屎钙畔?我可是專業(yè)的茫陆。”

/**
 * Created by w1992wishes on 2017/10/31.
 */
public class SimpleCakeFacroty {
    public static Cake createCake(String type){
        Cake cake;
        if ("cheese".equals(type)) {
            cake = new CheeseCake();
        } else if ("fruit".equals(type)) {
            cake = new FruitCake();
        } else if ("cream".equals(type)) {
            cake = new CreamCake();
        } else {
            cake = new DefaultCake();
        }
        return cake;
    }
}

你將創(chuàng)建蛋糕的過(guò)程挪到了一個(gè)叫SimpleCakeFactory類中擎析,于是CakeStore便這樣了:

public class CakeStore {
    public Cake orderCake(String type) {
        Cake cake;
        cake = SimpleCakeFacroty.createCake(type);
        cake.bake();
        cake.box();
        return cake;
    }
}

當(dāng)然看上去只是將創(chuàng)建Cake對(duì)象從CakeStore挪到了SimpleCakeFactory簿盅,似乎并沒(méi)有太多變化。如果新增蛋糕似乎還需要新增else if揍魂,破壞了“對(duì)擴(kuò)展開放桨醋,對(duì)修改關(guān)閉”的原則。

但簡(jiǎn)單工廠的加入使蛋糕的生產(chǎn)和蛋糕的使用分開了现斋,同時(shí)新開蛋糕店時(shí)喜最,也可以重新復(fù)用SimpleCakeFactory中的方法,減少了大量重復(fù)代碼庄蹋,而且每次新增蛋糕瞬内,只需要修改SimpleCakeFactory一個(gè)類就好了,這些都是優(yōu)點(diǎn)呢限书。

四虫蝶、模式的結(jié)構(gòu)

有了上面的蛋糕店的例子后,再來(lái)總結(jié)一下簡(jiǎn)單工廠模式的結(jié)構(gòu)倦西。

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

  • SimpleFactory(工廠角色):工廠角色即工廠類能真,它是簡(jiǎn)單工廠模式的核心,負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有產(chǎn)品實(shí)例的內(nèi)部邏輯扰柠;工廠類可以被外界直接調(diào)用粉铐,創(chuàng)建所需的產(chǎn)品對(duì)象;在工廠類中提供了靜態(tài)的工廠方法createProduct()卤档,它的返回類型為抽象產(chǎn)品類型Product蝙泼。
  • Product(抽象產(chǎn)品角色):它是工廠類所創(chuàng)建的所有對(duì)象的父類,封裝了各種產(chǎn)品對(duì)象的公有方法劝枣,它的引入將提高系統(tǒng)的靈活性汤踏,使得在工廠類中只需定義一個(gè)通用的工廠方法倡缠,因?yàn)樗袆?chuàng)建的具體產(chǎn)品對(duì)象都是其子類對(duì)象。
  • ConcreteProduct(具體產(chǎn)品角色):它是簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo)茎活,所有被創(chuàng)建的對(duì)象都充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例昙沦。每一個(gè)具體產(chǎn)品角色都繼承了抽象產(chǎn)品角色,需要實(shí)現(xiàn)在抽象產(chǎn)品中聲明的抽象方法载荔。

在簡(jiǎn)單工廠模式中盾饮,客戶端通過(guò)工廠類來(lái)創(chuàng)建一個(gè)產(chǎn)品類的實(shí)例,而無(wú)須直接使用new關(guān)鍵字來(lái)創(chuàng)建對(duì)象懒熙,它是工廠模式家族中最簡(jiǎn)單的一員丘损。

五、代碼示例

上面蛋糕的例子可以看作一個(gè)簡(jiǎn)單示例工扎,這里簡(jiǎn)單再列一個(gè):

典型的抽象產(chǎn)品類代碼

/**
 * Created by w1992wishes on 2017/11/1.
 */
public abstract class Product {
    public void methodSame() {
        //公共方法的實(shí)現(xiàn)  
    }

    //聲明抽象業(yè)務(wù)方法
    public abstract void methodDiff();
}

在具體產(chǎn)品類中實(shí)現(xiàn)了抽象產(chǎn)品類中聲明的抽象業(yè)務(wù)方法徘钥,不同的具體產(chǎn)品類可以提供不同的實(shí)現(xiàn),典型的具體產(chǎn)品類代碼

/**
 * Created by w1992wishes on 2017/11/1.
 */
public class ConcreteProductA extends Product {
    @Override
    public void methodDiff() {
        //業(yè)務(wù)方法的實(shí)現(xiàn)  
    }
}
/**
 * Created by w1992wishes on 2017/11/1.
 */
public class ConcreteProductB extends Product {
    @Override
    public void methodDiff() {
        //業(yè)務(wù)方法的實(shí)現(xiàn)  
    }
}

簡(jiǎn)單工廠模式的核心是工廠類肢娘,在沒(méi)有工廠類之前呈础,客戶端一般會(huì)使用new關(guān)鍵字來(lái)直接創(chuàng)建產(chǎn)品對(duì)象,而在引入工廠類之后橱健,客戶端可以通過(guò)工廠類來(lái)創(chuàng)建產(chǎn)品而钞,在簡(jiǎn)單工廠模式中,工廠類提供了一個(gè)靜態(tài)工廠方法供客戶端使用拘荡,根據(jù)所傳入的參數(shù)不同可以創(chuàng)建不同的產(chǎn)品對(duì)象臼节,典型的工廠類代碼

/**
 * Created by w1992wishes on 2017/11/1.
 */
public class SimpleFactory {
    //靜態(tài)工廠方法  
    public static Product getProduct(String arg) {
        Product product = null;
        if (arg.equalsIgnoreCase("A")) {
            product = new ConcreteProductA();
            //初始化設(shè)置product  
        }
        else if (arg.equalsIgnoreCase("B")) {
            product = new ConcreteProductB();
            //初始化設(shè)置product  
        }
        return product;
    }
}

在客戶端代碼中,我們通過(guò)調(diào)用工廠類的工廠方法即可得到產(chǎn)品對(duì)象珊皿,典型代碼

class Client {  
    public static void main(String args[]) {  
        Product product;   
        product = Factory.getProduct("A"); //通過(guò)工廠類創(chuàng)建產(chǎn)品對(duì)象  
        product.methodSame();  
        product.methodDiff();  
    }  
}

六网缝、優(yōu)點(diǎn)和缺點(diǎn)

6.1、優(yōu)點(diǎn)

  • 工廠類含有必要的判斷邏輯蟋定,可以決定在什么時(shí)候創(chuàng)建哪一個(gè)產(chǎn)品類的實(shí)例粉臊,客戶端可以免除直接創(chuàng)建產(chǎn)品對(duì)象的責(zé)任,而僅僅“消費(fèi)”產(chǎn)品溢吻;簡(jiǎn)單工廠模式通過(guò)這種做法實(shí)現(xiàn)了對(duì)責(zé)任的分割维费,它提供了專門的工廠類用于創(chuàng)建對(duì)象果元。
  • 客戶端無(wú)須知道所創(chuàng)建的具體產(chǎn)品類的類名促王,只需要知道具體產(chǎn)品類所對(duì)應(yīng)的參數(shù)即可,對(duì)于一些復(fù)雜的類名而晒,通過(guò)簡(jiǎn)單工廠模式可以減少使用者的記憶量蝇狼。
  • 通過(guò)引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類倡怎,在一定程度上提高了系統(tǒng)的靈活性迅耘。

6.2贱枣、缺點(diǎn)

  • 由于工廠類集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作颤专,整個(gè)系統(tǒng)都要受到影響纽哥。
  • 使用簡(jiǎn)單工廠模式將會(huì)增加系統(tǒng)中類的個(gè)數(shù),在一定程序上增加了系統(tǒng)的復(fù)雜度和理解難度栖秕。
  • 系統(tǒng)擴(kuò)展困難春塌,一旦添加新產(chǎn)品就不得不修改工廠邏輯,同樣破壞了“開閉原則”簇捍;在產(chǎn)品類型較多時(shí)只壳,有可能造成工廠邏輯過(guò)于復(fù)雜,不利于系統(tǒng)的擴(kuò)展和維護(hù)暑塑。
  • 簡(jiǎn)單工廠模式由于使用了靜態(tài)工廠方法,造成工廠角色無(wú)法形成基于繼承的等級(jí)結(jié)構(gòu)事格。

七惕艳、適用環(huán)境

在以下情況下可以使用簡(jiǎn)單工廠模式:

  • 工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少:由于創(chuàng)建的對(duì)象較少,不會(huì)造成工廠方法中的業(yè)務(wù)邏輯太過(guò)復(fù)雜驹愚。
  • 客戶端只知道傳入工廠類的參數(shù)尔艇,對(duì)于如何創(chuàng)建對(duì)象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細(xì)節(jié),甚至連類名都不需要記住么鹤,只需要知道類型所對(duì)應(yīng)的參數(shù)终娃。

八、模式應(yīng)用

  • JDK類庫(kù)中廣泛使用了簡(jiǎn)單工廠模式蒸甜,如工具類java.text.DateFormat棠耕,它用于格式化一個(gè)本地日期或者時(shí)間。
public final static DateFormat getDateInstance(); 
public final static DateFormat getDateInstance(int style); 
public final static DateFormat getDateInstance(int style,Locale locale); 
  • 獲取不同加密算法的密鑰生成器柠新。
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
  • 創(chuàng)建密碼器窍荧。
Cipher cp=Cipher.getInstance("DESede");

九、總結(jié)

  • 創(chuàng)建型模式對(duì)類的實(shí)例化過(guò)程進(jìn)行了抽象恨憎,能夠?qū)?duì)象的創(chuàng)建與對(duì)象的使用過(guò)程分離蕊退。
  • 簡(jiǎn)單工廠模式又稱為靜態(tài)工廠方法模式,它屬于類創(chuàng)建型模式憔恳。在簡(jiǎn)單工廠模式中瓤荔,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例。簡(jiǎn)單工廠模式專門定義一個(gè)類來(lái)負(fù)責(zé)創(chuàng)建其他類的實(shí)例钥组,被創(chuàng)建的實(shí)例通常都具有共同的父類输硝。
  • 簡(jiǎn)單工廠模式包含三個(gè)角色:工廠角色負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯;抽象產(chǎn)品角色是所創(chuàng)建的所有對(duì)象的父類程梦,負(fù)責(zé)描述所有實(shí)例所共有的公共接口点把;具體產(chǎn)品角色是創(chuàng)建目標(biāo)橘荠,所有創(chuàng)建的對(duì)象都充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例。
  • 簡(jiǎn)單工廠模式的要點(diǎn)在于:當(dāng)你需要什么郎逃,只需要傳入一個(gè)正確的參數(shù)哥童,就可以獲取你所需要的對(duì)象,而無(wú)須知道其創(chuàng)建細(xì)節(jié)褒翰。
  • 簡(jiǎn)單工廠模式最大的優(yōu)點(diǎn)在于實(shí)現(xiàn)對(duì)象的創(chuàng)建和對(duì)象的使用分離如蚜,將對(duì)象的創(chuàng)建交給專門的工廠類負(fù)責(zé),但是其最大的缺點(diǎn)在于工廠類不夠靈活影暴,增加新的具體產(chǎn)品需要修改工廠類的判斷邏輯代碼错邦,而且產(chǎn)品較多時(shí),工廠方法代碼將會(huì)非常復(fù)雜型宙。
  • 簡(jiǎn)單工廠模式適用情況包括:工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少撬呢;客戶端只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象不關(guān)心妆兑。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末魂拦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子搁嗓,更是在濱河造成了極大的恐慌芯勘,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腺逛,死亡現(xiàn)場(chǎng)離奇詭異荷愕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)棍矛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門安疗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人够委,你說(shuō)我怎么就攤上這事荐类。” “怎么了茁帽?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵玉罐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我潘拨,道長(zhǎng)吊输,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任战秋,我火速辦了婚禮璧亚,結(jié)果婚禮上讨韭,老公的妹妹穿的比我還像新娘脂信。我一直安慰自己癣蟋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布狰闪。 她就那樣靜靜地躺著疯搅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埋泵。 梳的紋絲不亂的頭發(fā)上幔欧,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音丽声,去河邊找鬼礁蔗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雁社,可吹牛的內(nèi)容都是我干的浴井。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼霉撵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼磺浙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起徒坡,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撕氧,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后喇完,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伦泥,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年锦溪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奄喂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡海洼,死狀恐怖跨新,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坏逢,我是刑警寧澤域帐,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站是整,受9級(jí)特大地震影響肖揣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浮入,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一龙优、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧事秀,春花似錦彤断、人聲如沸野舶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)平道。三九已至,卻和暖如春供炼,著一層夾襖步出監(jiān)牢的瞬間一屋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工袋哼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冀墨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓涛贯,卻偏偏與公主長(zhǎng)得像轧苫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疫蔓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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