看透 "工廠方法" 模式

1.引入

考慮一個(gè)應(yīng)用程序類Application,支持創(chuàng)建文本文檔,編輯文本文檔等操作雅任。

public class TextDocument{  
        public void editDocument(){
                .........
        }

        public void saveDocument(){
                .........
        }
}

public class Application{
        private TextDocument mDoc;

        public TextDocument createDocument(){
                mDoc = new TextDocument();
        }

        public boolean isDocumentAvailable(){
                return mDoc != null;
        }

        public void editDocument(){
                mDoc.editDocument();
        }

        public void saveDocument(){
                mDoc.saveDocument();
        }
}

對(duì)象關(guān)系如下圖所示:

對(duì)象關(guān)系.png

現(xiàn)在辽幌,如果我們想添加對(duì)image文檔的支持,我們?nèi)绾卧O(shè)計(jì)程序呢椿访。從設(shè)計(jì)模式的核心思想(封裝變化乌企,解耦具體實(shí)現(xiàn))出發(fā),擴(kuò)展程序我們需要兩步成玫。
1.封裝變化 將程序中可能因?yàn)樾枨笞兓瘜?dǎo)致代碼變動(dòng)的部分封裝到具體類中加酵。針對(duì)上述示例,如果添加對(duì)image文檔的支持哭当,創(chuàng)建文檔部分的代碼需要調(diào)整猪腕,所以我們將創(chuàng)建TextDocument的操作封裝到類中,命名 TextDocumentFactory

public class TextDocument{  
        public void editDocument(){
                .........
        }

        public void saveDocument(){
                .........
        }
}

public class TextDocumentFactory{
        public TextDocument createDocument(){
                return new TextDocument();
        }
}

public class Application{
        private TextDocument mDoc;

        public TextDocument createDocument(TextDocumentFactory factory){
                mDoc =factory.createDocument();
        }

        public boolean isDocumentAvailable(){
                return mDoc != null;
        }

        public void editDocument(){
                mDoc.editDocument();
        }

        public void saveDocument(){
                mDoc.saveDocument();
        }
}

對(duì)象關(guān)系如下圖所示:

對(duì)象關(guān)系引入TextDocumentFactory.png

2.解耦具體實(shí)現(xiàn) 根據(jù)面向接口編程原則,在Application和TextDocumentFactory之間引入一個(gè)抽象接口類DocumentFactory钦勘,就可以隔離Application和具體的XXXDocumentFactory之間的耦合關(guān)系陋葡。通過創(chuàng)建不同的DocumentFactory子類,我們就可以支持不同的文檔類型彻采。

public interface Document{
        void editDocument();
        void saveDocument();
}

/**
* text 文檔
**/
public class TextDocument implements Document {  
        public void editDocument(){
                .........
        }

        public void saveDocument(){
                .........
        }
}

/**
* image 文檔
**/
public class ImageDocument implements Document {  
        public void editDocument(){
                .........
        }

        public void saveDocument(){
                .........
        }
}

public interface DocumentFactory{
        Document createDocument();
}

/**
*  text 文檔 工廠
**/
public class TextDocumentFactory implements DocumentFactory {
        public TextDocument createDocument(){
                return new TextDocument();
        }
}

/**
*  image 文檔 工廠
**/
public class ImageDocumentFactory implements DocumentFactory {
        public TextDocument createDocument(){
                return new TextDocument();
        }
}

public class Application{
        private TextDocument mDoc;

        public TextDocument createDocument(TextDocumentFactory factory){
                mDoc =factory.createDocument();
        }

        public boolean isDocumentAvailable(){
                return mDoc != null;
        }

        public void editDocument(){
                mDoc.editDocument();
        }

        public void saveDocument(){
                mDoc.saveDocument();
        }
}

對(duì)象關(guān)系如下圖所示:

工廠方法模式.png

這樣腐缤,我們不僅很好支持了image文檔的操作,還為其他各種文檔的支持預(yù)留了擴(kuò)展肛响。

反思文章剛開始作者遇到的問題岭粤,你會(huì)發(fā)現(xiàn),在開發(fā)項(xiàng)目的過程中特笋,經(jīng)常會(huì)遇到類似的情況剃浇。解決問題的思路很重要,但是,我們依然為上面的解決方案(類之間的關(guān)系模式)定義了一個(gè)名字---工廠方法模式

2.定義

基類中包含一個(gè)創(chuàng)建對(duì)象的接口(方法)虎囚,具體創(chuàng)建何種類型的對(duì)象延遲到子類實(shí)現(xiàn)角塑。類之間的這種關(guān)系模式,我們稱為工廠方法模式淘讥。

3.實(shí)現(xiàn)

從細(xì)節(jié)上來說圃伶,工廠方法有三種不同的實(shí)現(xiàn)方式。
1.抽象工廠不提供工廠方法的缺省實(shí)現(xiàn)适揉。它避免了不得不實(shí)例化不可預(yù)見類的問題。
2.抽象工廠提供工廠方法的缺省實(shí)現(xiàn)煤惩。它遵循的準(zhǔn)則是,"用一個(gè)獨(dú)立的操作創(chuàng)建對(duì)象嫉嘀,這樣子類才能重定義它們的創(chuàng)建方式"
3.參數(shù)化工廠方法。工廠方法接收一個(gè)標(biāo)識(shí)要被創(chuàng)建的對(duì)象種類的參數(shù)魄揉,這樣剪侮,工廠方法就可以創(chuàng)建多種產(chǎn)品。重定義一個(gè)參數(shù)化的工廠方法使你可以簡(jiǎn)單而有選擇性的擴(kuò)展或改變一個(gè)工廠生產(chǎn)的產(chǎn)品洛退。
一個(gè)參數(shù)化的工廠方法具有如下的一般形式瓣俯,此處 MyDocument和YourDocument是Document的子類:

public class DocumentFactory {
        public Document createDocument(DocumentId id){
            if (id == MINE) return new MyDocument();
            if (id == YOURS) return new YourDocument();

            return null;
        }
}

我們可以通過創(chuàng)建DocumentFactory子類的方式交換MyDocument和YourDocument并且支持一個(gè)新的子類TheirDocument:

public class MyDocumentFactory extends DocumentFactory {
        public Document createDocument(DocumentId id){
            if (id == YOURS) return new MyDocument();
            if (id == MINE) return new YourDocument();
                 // switch YOURS and MINE


            if (id == THEIRS) return new TheirDocument();

            return super.createDocument(id);
        }
}

注意這個(gè)操作所做的最后一件事是調(diào)用父類的createDocument。這是因?yàn)镸yDocumentFactory.createDocument僅在對(duì)YOURS , MINE 和THEIRS的處理上和父類不同兵怯。它對(duì)其他類不感興趣彩匕。因此 MyDocumentFactory 擴(kuò)展了所創(chuàng)建產(chǎn)品的種類,并且將除少數(shù)產(chǎn)品以外所有產(chǎn)品的創(chuàng)建職責(zé)延遲給了父類媒区。

4.效果

工廠方法不再將與特定實(shí)現(xiàn)有關(guān)的類綁定到你的代碼中驼仪。代碼僅處理Document接口;因此它可以與用戶定義的任何ConcreteDocument類一起使用袜漩。
工廠方法的一個(gè)潛在缺點(diǎn)在于客戶可能僅僅為了創(chuàng)建一個(gè)特定的ConcreteDocument對(duì)象绪爸,就不得不創(chuàng)建DocumentFactory的子類。

為子類提供hook宙攻。用工廠方法在一個(gè)類的內(nèi)部創(chuàng)建對(duì)象通常比直接創(chuàng)建對(duì)象更靈活奠货。Factory Method給子類一個(gè)hook以提供對(duì)象的擴(kuò)展版本。
在Document的例子中座掘,Document類可以定義一個(gè)稱為createFileDialog的工廠方法递惋,該方法為打開一個(gè)已有的文檔創(chuàng)建默認(rèn)的文件對(duì)話框?qū)ο蟆ocument的子類可以重定義這個(gè)工廠方法以定義一個(gè)與特定應(yīng)用相關(guān)的文件對(duì)話框溢陪。在這種情況下丹墨,工廠方法就不再抽象了而是提供了一個(gè)合理的缺省實(shí)現(xiàn)。

5.后記

很多人建議我多舉幾個(gè)工廠方法的例子嬉愧,加深理解贩挣。但是我的理論是,看透一個(gè)例子,理解其中的精髓王财,用剩下的時(shí)間卵迂,多用用不同的模式設(shè)計(jì)程序,你才可以事半功倍绒净。建議讀懂见咒,經(jīng)常重復(fù)溫習(xí)上面的文章,每一個(gè)字對(duì)于理解工廠方法模式都有一定的分量挂疆,加油改览!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缤言,隨后出現(xiàn)的幾起案子宝当,更是在濱河造成了極大的恐慌,老刑警劉巖胆萧,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庆揩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡跌穗,警方通過查閱死者的電腦和手機(jī)订晌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門颓帝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谋梭,“玉大人,你說我怎么就攤上這事昭雌「耄” “怎么了推励?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)肉迫。 經(jīng)常有香客問我验辞,道長(zhǎng),這世上最難降的妖魔是什么喊衫? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任跌造,我火速辦了婚禮,結(jié)果婚禮上族购,老公的妹妹穿的比我還像新娘壳贪。我一直安慰自己,他們只是感情好寝杖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布违施。 她就那樣靜靜地躺著,像睡著了一般瑟幕。 火紅的嫁衣襯著肌膚如雪磕蒲。 梳的紋絲不亂的頭發(fā)上留潦,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音辣往,去河邊找鬼兔院。 笑死,一個(gè)胖子當(dāng)著我的面吹牛站削,可吹牛的內(nèi)容都是我干的坊萝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼许起,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼十偶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起园细,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤惦积,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后珊肃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荣刑,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馅笙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年伦乔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片董习。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烈和,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出皿淋,到底是詐尸還是另有隱情招刹,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布窝趣,位于F島的核電站疯暑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哑舒。R本人自食惡果不足惜妇拯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洗鸵。 院中可真熱鬧越锈,春花似錦、人聲如沸膘滨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽火邓。三九已至丹弱,卻和暖如春德撬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹈矮。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工砰逻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泛鸟。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓蝠咆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親北滥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刚操,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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