【設(shè)計模式】簡單工廠模式

介紹

工廠模式是最常用的一類創(chuàng)建型設(shè)計模式茫打,通常我們所說的工廠模式是指工廠方法模式蛉鹿,它也是使用頻率最高的工廠模式布隔。本文描述的簡單工廠模式是工廠方法模式的“小弟”讳推,它不屬于GoF 23種設(shè)計模式汉柒,但在軟件開發(fā)中應(yīng)用也較為頻繁瘦锹,通常將它作為學(xué)習(xí)其他工廠模式的入門错沃。此外跌前,工廠方法模式還有一位“大哥”——抽象工廠模式昼蛀。這三種工廠模式各具特色宴猾,難度也逐個加大,在軟件開發(fā)中它們都得到了廣泛的應(yīng)用叼旋,成為面向?qū)ο筌浖谐S玫膭?chuàng)建對象的工具鳍置。

定義

定義一個工廠類,它可以根據(jù)參數(shù)的不同返回不同類的實例送淆,被創(chuàng)建的實例通常都具有共同的父類税产。因為在簡單工廠模式中用于創(chuàng)建實例的方法是靜態(tài)(static)方法,因此簡單工廠模式又被稱為靜態(tài)工廠方法(Static Factory Method)模式,它屬于類創(chuàng)建型模式辟拷。

如何使用

首先將需要創(chuàng)建的各種不同類似對象的相關(guān)代碼封裝到不同的類中撞羽,這些類稱為具體產(chǎn)品類,而將它們公共的代碼進(jìn)行抽象和提取后封裝在一個抽象產(chǎn)品類中衫冻,每一個具體產(chǎn)品類都是抽象產(chǎn)品類的子類诀紊;然后提供一個工廠類用于創(chuàng)建各種產(chǎn)品,在工廠類中提供一個創(chuàng)建產(chǎn)品的工廠方法隅俘,該方法可以根據(jù)所傳入的參數(shù)不同創(chuàng)建不同的具體產(chǎn)品對象邻奠;客戶端只需調(diào)用工廠類的工廠方法并傳入相應(yīng)的參數(shù)即可得到一個產(chǎn)品對象。

UML類圖
Alt 簡單工廠模式結(jié)構(gòu)圖
角色介紹
  • Factory(工廠角色):工廠角色即工廠類为居,它是簡單工廠模式的核心碌宴,負(fù)責(zé)實現(xiàn)創(chuàng)建所有產(chǎn)品實例的內(nèi)部邏輯;工廠類可以被外界直接調(diào)用蒙畴,創(chuàng)建所需的產(chǎn)品對象贰镣;在工廠類中提供了靜態(tài)的工廠方法factoryMethod(),它的返回類型為抽象產(chǎn)品類型Product膳凝。簡單工廠模式的核心是工廠類碑隆,在沒有工廠類之前,客戶端一般會使用new關(guān)鍵字來直接創(chuàng)建產(chǎn)品對象蹬音,而在引入工廠類之后上煤,客戶端可以通過工廠類來創(chuàng)建產(chǎn)品,在簡單工廠模式中著淆,工廠類提供了一個靜態(tài)工廠方法供客戶端使用楼入,根據(jù)所傳入的參數(shù)不同可以創(chuàng)建不同的產(chǎn)品對象
  • Product(抽象產(chǎn)品角色):它是工廠類所創(chuàng)建的所有對象的父類,封裝了各種產(chǎn)品對象的公有方法牧抽,它的引入將提高系統(tǒng)的靈活性,使得在工廠類中只需定義一個通用的工廠方法遥赚,因為所有創(chuàng)建的具體產(chǎn)品對象都是其子類對象扬舒。
  • ConcreteProduct(具體產(chǎn)品角色):它是簡單工廠模式的創(chuàng)建目標(biāo),所有被創(chuàng)建的對象都充當(dāng)這個角色的某個具體類的實例凫佛。每一個具體產(chǎn)品角色都繼承了抽象產(chǎn)品角色讲坎,需要實現(xiàn)在抽象產(chǎn)品中聲明的抽象方法。
方案優(yōu)化

問題:每當(dāng)新增加一種類型的產(chǎn)品愧薛,都需要修改靜態(tài)工廠方法的參數(shù)晨炕,違法了“開閉原則”。我們可以將靜態(tài)工廠方法的參數(shù)存儲在配置文件中毫炉,使用一個工具類來讀取配置文件中的字符串參數(shù)瓮栗,如果需要更換具體圖標(biāo)對象,只需要修改配置文件,無需修改任何源代碼费奸,符合“開閉原則”弥激。

簡單工廠模式的簡化

有時候,為了簡化簡單工廠模式愿阐,我們可以將抽象產(chǎn)品類和工廠類合并微服,將靜態(tài)工廠方法移至抽象產(chǎn)品類中。



客戶端可以通過產(chǎn)品父類的靜態(tài)工廠方法缨历,根據(jù)參數(shù)的不同創(chuàng)建不同類型的產(chǎn)品子類對象以蕴。

demo代碼
//抽象圖表接口:抽象產(chǎn)品類  
interface Chart {  
    public void display();  
}  
  
//柱狀圖類:具體產(chǎn)品類  
class HistogramChart implements Chart {  
    public HistogramChart() {  
        System.out.println("創(chuàng)建柱狀圖!");  
    }  
      
    public void display() {  
        System.out.println("顯示柱狀圖辛孵!");  
    }  
}  
  
//餅狀圖類:具體產(chǎn)品類  
class PieChart implements Chart {  
    public PieChart() {  
        System.out.println("創(chuàng)建餅狀圖丛肮!");  
    }  
      
    public void display() {  
        System.out.println("顯示餅狀圖!");  
    }  
}  
  
//折線圖類:具體產(chǎn)品類  
class LineChart implements Chart {  
    public LineChart() {  
        System.out.println("創(chuàng)建折線圖觉吭!");  
    }  
      
    public void display() {  
        System.out.println("顯示折線圖腾供!");  
    }  
}  
  
//圖表工廠類:工廠類  
class ChartFactory {  
    //靜態(tài)工廠方法  
    public static Chart getChart(String type) {  
        Chart chart = null;  
        if (type.equalsIgnoreCase("histogram")) {  
            chart = new HistogramChart();  
            System.out.println("初始化設(shè)置柱狀圖!");  
        }  
        else if (type.equalsIgnoreCase("pie")) {  
            chart = new PieChart();  
            System.out.println("初始化設(shè)置餅狀圖鲜滩!");  
        }  
        else if (type.equalsIgnoreCase("line")) {  
            chart = new LineChart();  
            System.out.println("初始化設(shè)置折線圖伴鳖!");              
        }  
        return chart;  
    }  
}  

編寫客戶端測試代碼

class Client {  
    public static void main(String args[]) {  
        Chart chart;  
        chart = ChartFactory.getChart("histogram"); //通過靜態(tài)工廠方法創(chuàng)建產(chǎn)品  
        chart.display();  
    }  
}  

用配置文件優(yōu)化方案改進(jìn)
如下config.xml所示:

<?xml version="1.0"?>  
<config>  
    <chartType>histogram</chartType>  
</config>  

再通過一個工具類XMLUtil來讀取配置文件中的字符串參數(shù),XMLUtil類的代碼如下所示:

public class XMLUtil {  
    //該方法用于從XML配置文件中提取圖表類型徙硅,并返回類型名  
    public static String getChartType() {  
        try {  
            //創(chuàng)建文檔對象  
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
            DocumentBuilder builder = dFactory.newDocumentBuilder();  
            Document doc;                             
            doc = builder.parse(new File("config.xml"));   
          
            //獲取包含圖表類型的文本節(jié)點  
            NodeList nl = doc.getElementsByTagName("chartType");  
            Node classNode = nl.item(0).getFirstChild();  
            String chartType = classNode.getNodeValue().trim();  
            return chartType;  
        }     
        catch(Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}  

在引入了配置文件和工具類XMLUtil之后榜聂,客戶端代碼修改如下:

class Client {  
    public static void main(String args[]) {  
        Chart chart;  
        String type = XMLUtil.getChartType(); //讀取配置文件中的參數(shù)  
        chart = ChartFactory.getChart(type); //創(chuàng)建產(chǎn)品對象  
        chart.display();  
    }  
}
總結(jié)
優(yōu)點
  • 工廠類包含必要的判斷邏輯,可以決定在什么時候創(chuàng)建哪一個產(chǎn)品類的實例嗓蘑,客戶端可以免除直接創(chuàng)建產(chǎn)品對象的職責(zé)须肆,而僅僅“消費”產(chǎn)品,簡單工廠模式實現(xiàn)了對象創(chuàng)建和使用的分離桩皿。
  • 客戶端無須知道所創(chuàng)建的具體產(chǎn)品類的類名豌汇,只需要知道具體產(chǎn)品類所對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名泄隔,通過簡單工廠模式可以在一定程度減少使用者的記憶量拒贱。
  • 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類佛嬉,在一定程度上提高了系統(tǒng)的靈活性逻澳。
缺點
  • 由于工廠類集中了所有產(chǎn)品的創(chuàng)建邏輯,職責(zé)過重暖呕,一旦不能正常工作斜做,整個系統(tǒng)都要受到影響。
  • 使用簡單工廠模式勢必會增加系統(tǒng)中類的個數(shù)(引入了新的工廠類)湾揽,增加了系統(tǒng)的復(fù)雜度和理解難度瓤逼。
  • 系統(tǒng)擴展困難笼吟,一旦添加新產(chǎn)品就不得不修改工廠邏輯,在產(chǎn)品類型較多時抛姑,有可能造成工廠邏輯過于復(fù)雜赞厕,不利于系統(tǒng)的擴展和維護。
  • 簡單工廠模式由于使用了靜態(tài)工廠方法定硝,造成工廠角色無法形成基于繼承的等級結(jié)構(gòu)皿桑。
適用場景
  • 工廠類負(fù)責(zé)創(chuàng)建的對象比較少,由于創(chuàng)建的對象較少蔬啡,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜诲侮。
  • 客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象并不關(guān)心箱蟆。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沟绪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子空猜,更是在濱河造成了極大的恐慌绽慈,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辈毯,死亡現(xiàn)場離奇詭異坝疼,居然都是意外死亡,警方通過查閱死者的電腦和手機谆沃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門钝凶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唁影,你說我怎么就攤上這事耕陷。” “怎么了据沈?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵哟沫,是天一觀的道長。 經(jīng)常有香客問我锌介,道長嗜诀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任掏湾,我火速辦了婚禮,結(jié)果婚禮上肿嘲,老公的妹妹穿的比我還像新娘融击。我一直安慰自己,他們只是感情好雳窟,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布尊浪。 她就那樣靜靜地躺著匣屡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拇涤。 梳的紋絲不亂的頭發(fā)上捣作,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音鹅士,去河邊找鬼券躁。 笑死,一個胖子當(dāng)著我的面吹牛掉盅,可吹牛的內(nèi)容都是我干的也拜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼趾痘,長吁一口氣:“原來是場噩夢啊……” “哼慢哈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起永票,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤卵贱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后侣集,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體键俱,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年肚吏,在試婚紗的時候發(fā)現(xiàn)自己被綠了方妖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡罚攀,死狀恐怖党觅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斋泄,我是刑警寧澤杯瞻,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站炫掐,受9級特大地震影響魁莉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜募胃,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一旗唁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痹束,春花似錦检疫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夺溢。三九已至,卻和暖如春烛谊,著一層夾襖步出監(jiān)牢的瞬間风响,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工丹禀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留状勤,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓湃崩,卻偏偏與公主長得像荧降,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子攒读,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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