Java設(shè)計(jì)模式-創(chuàng)建型模式-工廠方法模式

此系列文章為清華大學(xué)出版社出版劉偉編著《Java設(shè)計(jì)模式》的學(xué)習(xí)筆記贷痪。

>>全部23種設(shè)計(jì)模式<<

1 概述

工廠方法模式簡稱為工廠模式(Factory Pattern),又可稱為虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)。工廠方法模式是一種創(chuàng)建型模式扇谣,在工廠方法模式中,工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類負(fù)責(zé)生成具體的產(chǎn)品對象弹惦,這樣做的目的時(shí)將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應(yīng)該實(shí)例化哪一個(gè)具體的產(chǎn)品類悄但。

工廠方法模式:定義一個(gè)用于創(chuàng)建對象的接口棠隐,但是讓子類決定將哪一個(gè)類實(shí)例化。工廠方法模式讓一個(gè)類的實(shí)例化延遲到其子類檐嚣。

2 結(jié)構(gòu)與實(shí)現(xiàn)

2.1 工廠方法模式結(jié)構(gòu)

抽象工廠模式包含4個(gè)角色

  1. AbstractProduct(抽象產(chǎn)品):它是定義產(chǎn)品的接口助泽,是工廠方法模式所創(chuàng)建對象的超類,是具體產(chǎn)品對象的公共父類嚎京∥撕兀可以是抽象類或者接口。
  2. ConcreteProduct(具體產(chǎn)品):它實(shí)現(xiàn)了抽象產(chǎn)品所定義的接口鞍帝,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建诫睬,<span style="color:red;font-weight:900">具體工廠和具體產(chǎn)品之間一一對應(yīng)</span>。
  3. AbstractFactory(抽象工廠):在抽象工廠中聲明了抽象工廠方法帕涌,用于返回一個(gè)產(chǎn)品摄凡。抽象工廠是工廠方法模式的核心续徽,所有創(chuàng)建對象的工廠類都必須實(shí)現(xiàn)該接口。
  4. ConcreteFactory(具體工廠):它是抽象工廠類的子類亲澡,實(shí)現(xiàn)了在抽象工廠中聲明的工廠方法钦扭,并可由客戶端調(diào)用,返回一個(gè)具體產(chǎn)品類的實(shí)例床绪。

2.2 工廠方法模式舉例

一客情、背景介紹

某系統(tǒng)運(yùn)行日志記錄器(Logger)可以通過多種途徑保存系統(tǒng)的運(yùn)行日志,例如通過文件記錄或數(shù)據(jù)庫記錄癞己,用戶可以通過修改配置文件靈活地更換日志記錄方式膀斋。在設(shè)計(jì)各類日志記錄器時(shí),開發(fā)人員發(fā)現(xiàn)需要對日志記錄器時(shí)末秃,開發(fā)人員發(fā)現(xiàn)需要對日志記錄器進(jìn)行一些初始化工作概页,初始化參數(shù)地設(shè)置過程較為復(fù)雜,而且某些參數(shù)地設(shè)置有嚴(yán)格地先后次序 练慕,否則可能會發(fā)生記錄失敗惰匙。

為了更好地封裝記錄器的初始化過程并保證多種記錄器切換的靈活性,現(xiàn)使用工廠方法模式設(shè)計(jì)該系統(tǒng)(注:在Java中常用的日志記錄工具有SLF4J铃将、Log4j项鬼、GCLogViewer、Logstash等劲阎。)

二绘盟、項(xiàng)目結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu).png

三、抽象產(chǎn)品

public interface Logger {
    public void writeLog();
}

四悯仙、具體產(chǎn)品

具體日志記錄器:數(shù)據(jù)庫日志記錄器

public class DatabaseLogger implements Logger {
    @Override
    public void writeLog() {
        System.out.println("數(shù)據(jù)庫日志記錄");
    }
}

具體日志記錄器:文件日志記錄器

public class FileLogger implements Logger {
    @Override
    public void writeLog() {
        System.out.println("文件日志記錄");
    }
}

五龄毡、抽象工廠

public interface LoggerFactory {
    public Logger createLogger();
}

六、具體工廠

具體工廠:數(shù)據(jù)庫日志記錄器工廠

public class DatabaseLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        //連接數(shù)據(jù)庫锡垄,創(chuàng)建數(shù)據(jù)庫日志記錄對象等操作沦零,代碼省略
        Logger logger = new DatabaseLogger();
        //寫入日志等操作,代碼省略
        return logger;
    }
}

具體工廠:文件日志記錄器工廠

public class FileLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        //創(chuàng)建文件日志記錄器對象货岭,代碼省略
        Logger logger = new FileLogger();
        //創(chuàng)建文件路操,代碼省略
        return logger;
    }
}

七、測試Client

import CreationalPattern.FactoryMethodPattern.AbstractFactory.LoggerFactory;
import CreationalPattern.FactoryMethodPattern.AbstractProduct.Logger;
import CreationalPattern.FactoryMethodPattern.ConcreteFactory.DatabaseLoggerFactory;
import CreationalPattern.FactoryMethodPattern.ConcreteFactory.FileLoggerFactory;

public class Client {
    public static void main(String[] args) {
        LoggerFactory factory;
        Logger logger;
        /**
         * note:可以引入文件讀取和反射加載機(jī)制千贯,提供一個(gè)專門的配置文件屯仗。
         * note:只需要修改具體的XxxLoggerFactory是哪一個(gè)即可實(shí)現(xiàn)生產(chǎn)兩種不同的Logger
         */
        factory = new FileLoggerFactory();//文件日志記錄
//        factory = new DatabaseLoggerFactory();//數(shù)據(jù)庫日志記錄
        logger = factory.createLogger();
        logger.writeLog();
    }
}

八、打印結(jié)果

我們只需要改變實(shí)現(xiàn)抽象工廠的具體工廠類型搔谴,即可創(chuàng)建不同的日志記錄器:


創(chuàng)建數(shù)據(jù)庫日志記錄器.png
創(chuàng)建文件日志記錄器.png

3 總結(jié)

工廠方法模式是簡單工廠模式的延申魁袜,它繼承了簡單工廠模式的優(yōu)點(diǎn),同時(shí)還彌補(bǔ)了簡單工廠模式的不足。工廠方法模式是使用頻率最高的設(shè)計(jì)模式之一峰弹,是很多開源框架和API類庫的核心模式距境。

3.1 工廠方法模式優(yōu)點(diǎn)

  1. 在工廠方法模式中,工廠方法用來創(chuàng)建客戶所需要的產(chǎn)品垮卓,同時(shí)還向客戶隱藏了哪種具體產(chǎn)品將被實(shí)例化這一細(xì)節(jié),用戶只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠师幕,無需關(guān)心創(chuàng)建細(xì)節(jié)粟按,甚至無需知道具體產(chǎn)品類的類名。
  2. 基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計(jì)是工廠方法模式的關(guān)鍵霹粥。它能夠 讓工廠自主確定創(chuàng)建何種產(chǎn)品對象灭将,而如何創(chuàng)建這個(gè)對象的細(xì)節(jié)完全封裝在具體工廠內(nèi)部。工廠方法模式之所以被稱為多態(tài)工廠模式后控,正式因?yàn)樗械木唧w的工廠類都具有同一抽象父類庙曙。
  3. 使用工廠方法模式的另一個(gè)優(yōu)點(diǎn)是在系統(tǒng)中加入新產(chǎn)品時(shí)無需修改抽象工廠和抽象產(chǎn)品提供的接口,無需修改客戶端浩淘,也無需修改其他的具體工廠和具體產(chǎn)品捌朴,而只需添加一個(gè)具體工廠和具體產(chǎn)品即可,這樣系統(tǒng)的可擴(kuò)展性也就變得非常好张抄,完全符合開閉原則砂蔽。

3.2 工廠方法模式確定

  1. 在添加新產(chǎn)品時(shí)需要編寫新的具體產(chǎn)品類,而且還要提供與之對應(yīng)的具體工廠類署惯,系統(tǒng)中類的個(gè)數(shù)成對增加左驾,在一定程度上增加了系統(tǒng)的復(fù)雜度,有更多的類需要編譯和運(yùn)行极谊,會給系統(tǒng)帶來額外的開銷诡右。
  2. 由于考慮到徐通的可擴(kuò)展性,需要引入抽象層轻猖,在客戶端代碼中均使用抽象層進(jìn)行定義帆吻,增加了系統(tǒng)的抽象性和理解難度。

3.3 工廠方法模式適用環(huán)境

  1. 客戶端不知道它所需要的對象的類蜕依。在工廠方法模式中桅锄,客戶端不需要知道具體產(chǎn)品類的類名,只需要知道對應(yīng)的工廠即可样眠,具體產(chǎn)品對象有具體工廠類創(chuàng)建友瘤,可將具體工廠 類的類名存儲在配置文件或數(shù)據(jù)庫中。
  2. 抽象工廠類通過其子類來指定創(chuàng)建哪個(gè)對象檐束。在工廠方法模式中辫秧,對于抽象工廠類只需要提供一個(gè)創(chuàng)建產(chǎn)品的接口,而由子類來確定具體要?jiǎng)?chuàng)建的對象被丧,利用面向?qū)ο蟮亩鄳B(tài)性和里氏替換原則盟戏,在程序運(yùn)行時(shí)子類對象將覆蓋父類對象绪妹,從而使得系統(tǒng)更容易擴(kuò)展。

>>全部23種設(shè)計(jì)模式<<

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柿究,一起剝皮案震驚了整個(gè)濱河市邮旷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝇摸,老刑警劉巖婶肩,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異貌夕,居然都是意外死亡律歼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門啡专,熙熙樓的掌柜王于貴愁眉苦臉地迎上來险毁,“玉大人,你說我怎么就攤上這事们童∨峡觯” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵病附,是天一觀的道長问窃。 經(jīng)常有香客問我,道長完沪,這世上最難降的妖魔是什么域庇? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮覆积,結(jié)果婚禮上听皿,老公的妹妹穿的比我還像新娘。我一直安慰自己宽档,他們只是感情好尉姨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吗冤,像睡著了一般又厉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上椎瘟,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天覆致,我揣著相機(jī)與錄音,去河邊找鬼肺蔚。 笑死煌妈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播璧诵,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼汰蜘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了之宿?” 一聲冷哼從身側(cè)響起族操,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎比被,沒想到半個(gè)月后坪创,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姐赡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柠掂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片项滑。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖涯贞,靈堂內(nèi)的尸體忽然破棺而出枪狂,到底是詐尸還是另有隱情,我是刑警寧澤宋渔,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布州疾,位于F島的核電站,受9級特大地震影響皇拣,放射性物質(zhì)發(fā)生泄漏严蓖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一氧急、第九天 我趴在偏房一處隱蔽的房頂上張望颗胡。 院中可真熱鬧,春花似錦吩坝、人聲如沸毒姨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弧呐。三九已至,卻和暖如春嵌纲,著一層夾襖步出監(jiān)牢的瞬間俘枫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工疹瘦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留崩哩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像邓嘹,于是被迫代替她去往敵國和親酣栈。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351

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