摘要:上章講的是創(chuàng)建型的設(shè)計模式,工廠方法上,這次要講的是另一本書關(guān)于工廠方法的一些概念以及案例模型等等。工廠方法模式假設(shè)你有一個關(guān)于個人事務(wù)管理的項目,功能之一是管理預(yù)約對象。
上章講的是創(chuàng)建型的設(shè)計模式,工廠方法(上),這次要講的是另一本書關(guān)于工廠方法的一些概念以及案例、模型等等。就像電影“風雨哈佛路”中那個老師提問,為什么要用另外的一張一張紙質(zhì)資料,而不直接用書籍。女主回答說,因為不同的資料匯集了不同人的思想。
工廠方法模式假設(shè)你有一個關(guān)于個人事務(wù)管理的項目,功能之一是管理預(yù)約對象(Appointment)?,F(xiàn)在要和另一個公司建立關(guān)系,需要一個叫做BloggsCal的格式來和他們交流預(yù)約相關(guān)的數(shù)據(jù)。但是你將來可能要面對更多的數(shù)據(jù)格式
在接口上可以立即定義兩個類,
1.Class ApptEncoder:數(shù)據(jù)編碼器,將Appointment轉(zhuǎn)換成一個專有格式
2.Class CommsManager:管理員類,用來獲取數(shù)據(jù)編碼器,并使用編碼器進行第三方通信
使用模型屬于來描述的話,CommsManager就是創(chuàng)建者(Creator),而ApptEncoder是產(chǎn)品(product)
那么如何得到一個具體的ApptEncoder對象?
CommsManager類負責生成BloggsApptEncoder對象,但是當你和合作方關(guān)系改變,被要求轉(zhuǎn)換系統(tǒng)來使用一個新的格式MegaCal時,那么代碼就需要做另外的改變了
class CommsManager{ const BLOGGS = 1; const MEGA = 2; private $mode =1; function __construct($mode){ $this->mode = $mode; } function getApptEncoder(){ switch($this->mode){ case (self::MEGA): return new MegaApptEncoder(); default: return new BloggsApptEncoder(); } } } $comms = new CommsManager(CommsManager::MEGA); $appt = $comms->getApptEncoder(); print $appt->encode();
在類中我們使用常量標志定義了腳本可能運行的兩個模式:MEGA和BLOGGS,在getApptEncoder()方法中使用switch語句來檢查$mode屬性,并實例化相關(guān)編碼器
但是這種方法還有一種小缺陷,通常情況下,創(chuàng)建對象需要指定條件,但是有時候條件語句會被當作Awful的“Code taste”,因為可能會導(dǎo)致重復(fù)的條件語句蔓延在代碼中。我們知道創(chuàng)建者已經(jīng)能夠提供交流日歷數(shù)據(jù)的功能,但是如果合作方要求提供頁眉和頁腳來約束每次預(yù)約,那該怎么辦?
結(jié)果是,你需要在上面的代碼中加入新的方法
function getHeaderText(){ switch($this->mode){ case (self::MEGA): return "This is Mega format header! "; default: return "This is Bloggs format header! "; } }
Obviously,這會使得它在getApptEncoder()方法同時使用時,重復(fù)地使用了switch判斷,一旦客戶要增加其它需求,那工作量以及冗余程度會更重
總結(jié)一下當前需要思考的:
1.在代碼運行時我們才知道要生成的對象類型(BloggsApptEncoder或者是MegaApptEncoder)
2.我們需要能夠相對輕松地加入一些新的產(chǎn)品類型(如新的業(yè)務(wù)處理方式SyncML)
3.每一個產(chǎn)品類型都可定制特定的功能(如上文提到的頁眉頁腳)
另外注意我們使用的條件語句,其實可以被多態(tài)替代,而工廠方法模式恰好能讓我們用繼承和多態(tài)來封裝具體產(chǎn)品的創(chuàng)建,黃菊花說,我們要為每種協(xié)議創(chuàng)建CommsManager的每一個子類,而每一個子類都要實現(xiàn)getApptEncoder方法
實現(xiàn)工廠方法模式把創(chuàng)建者類與要生產(chǎn)的產(chǎn)品分離開來。創(chuàng)建者是一個工廠類,其中定義了用于生成產(chǎn)品對象的類方法,如果沒有提供默認實現(xiàn),那么就由創(chuàng)建者類的子類來執(zhí)行實例化。一般來說,就是創(chuàng)建者類的每個子類實例化一個相應(yīng)產(chǎn)品子類
所以我們把CommsManager重新指定為抽象類,這樣就可以得到一個靈活的父類,并把所有特定協(xié)議相關(guān)的代碼放到具體的子類中
下面是簡化過的代碼:
abstract class ApptEncoder{ abstract function encode(); } class BloggsApptEncoder extends ApptEncoder{ function encode(){ return "Appointment data encode in BloggsCal format! "; } } abstract class CommsManager{ abstract class getHeaderText(); abstract class getApptEncoder(); abstract class getFooterText(); } class BloggsCommsManager extends CommsManager{ function getHeaderText(){ return "BloggsCal Header"; } function getHeaderText(){ return new BloggsApptEncoder(); } function getFooterText(){ return "BloggsCal Footer"; } }
現(xiàn)在當我們要求實現(xiàn)MegaCal時,只需要給CommsManager抽象類寫一個新的實現(xiàn)
注意到上面的創(chuàng)建者類與產(chǎn)品的層次結(jié)構(gòu)很相似,這是使用工廠方法模式的常見結(jié)果,形成了一種特殊的代碼重復(fù)。另一個問題是該模式可能會導(dǎo)致不必要的子類化,如果你為創(chuàng)建者創(chuàng)建子類的原因是為了實現(xiàn)工廠方法模式,那么最好再考慮一下(這就是為什么在例子中引入頁眉頁腳)
抽象工廠模式上面例子中我們只關(guān)注了預(yù)約功能。
我們通過加入更多編碼格式,使結(jié)構(gòu)“橫向”增長
如果想擴展功能,使其能夠處理待辦事宜和聯(lián)系人,那應(yīng)該讓它進行縱向增長
CommsManager抽象類定義了用于生成3個產(chǎn)品(ApptEncoder、TtdEncoder、ContactEncoder)的接口,我們需要先實現(xiàn)一個具體的創(chuàng)建者,然后才能創(chuàng)建一個特定類型的具體產(chǎn)品,下圖模型創(chuàng)建了BloggsCal格式的創(chuàng)建
下面是CommsManager和BloggsCommsManager的代碼
abstract class CommsManager{ abstract function getHeaderText(); abstract function getApptEncoder(); abstract function getTtdEncoder(); abstract function getContactEncoder(); abstract function getFooterText(); } class BloggsCommsManager extends CommsManager{ function getHeaderText(){ return "BloggsCal header "; } function getApptEncoder(){ return new BloggsApptEncoder(); } function getTtdEncoder(){ return new BloggsTtdEncoder(); } function getContactEncoder(){ return new BloggsContactEncoder(); } function getFooterText(){ return "BloggsCal footer "; } }
在這個例子中使用了工廠方法模式,getContactEncoder()是CommsManager的抽象方法,并在BloggsCommManager中實現(xiàn)。設(shè)計模式間經(jīng)常會這樣寫作:一個模式創(chuàng)建可以把它自己引入到另一個模式的上下文環(huán)境中,我們加入了對MegaCal格式的支持
這樣的模式帶來了什么?
1.系統(tǒng)與實現(xiàn)的細節(jié)分離開來,我們可以在實例中添加移除任意樹木的編碼格式而不會影響系統(tǒng)
2.對系統(tǒng)中功能相關(guān)的元素強制進行組合,因此通過使用BloggsCommsManager,可以確保值使用與BloggsCal相關(guān)的類
3.添加新產(chǎn)品比較麻煩,不僅要創(chuàng)建新產(chǎn)品的具體實現(xiàn),而且必須修改抽象創(chuàng)建者和它的每一個具體實現(xiàn)
我們可以創(chuàng)建一個使用標志來決定返回什么對象的單一make()方法,而不用給每個工廠方法創(chuàng)建獨立的方法,如下
abstract class CommsManager{ const APPT = 1; const TTD = 2; const CONTACT = 3; abstract function getHeaderText(); abstract function make($flag_int); abstract function getFooterText(); } class BloggsCommsManager extends CommsManager{ function getHeaderText(){ return "BloggsCal header"; } function make($flag_int){ switch($flag_int){ case self::APPT: return new BloggsApptEncoder(); case self::CONTACT: return new BloggsContactEncoder(); case self::TTD: return new BloggsTtdEncoder(); } } function getFooterText(){ return "BloggsCal footer "; } }
類的接口更加緊湊,但也有代價,在使用工廠方法時,我們定義了一個清晰的接口強制所有具體工廠對象遵循它,而使用丹儀的make()方法,我們必須在所有的具體創(chuàng)建者中支持所有的產(chǎn)品對象。每個具體創(chuàng)建者都必須實現(xiàn)相同的標志檢測(flag),客戶類無法確定具體的創(chuàng)建者是否可以生成所有產(chǎn)品,因為make方法需要對每種情況進行考慮并進行選擇
本章參考《深入PHP:面向?qū)ο?、模式與實踐》第9章
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/21259.html
摘要:利用工廠方法模式,請求者發(fā)出請求,而不具體創(chuàng)建產(chǎn)品。正是因為這個原因,使用工廠方法模式可以簡化復(fù)雜的創(chuàng)建過程,關(guān)鍵就在于它在維持一個公共接口。 創(chuàng)建型設(shè)計模式 包括以下五種: 抽象工廠 生成器 工廠方法 原型 單例 我們選擇工廠方法和原型模式作為將用PHP實現(xiàn)的創(chuàng)建型設(shè)計的例子工廠方法模式是這5個設(shè)計模式中唯一的一種類設(shè)計模式原型模式屬于對象類模式,可以使用PHP_clone方法實...
摘要:設(shè)計模式設(shè)計模式基本原則設(shè)計原則按接口而不是按實現(xiàn)來編程按接口而不是按實現(xiàn)編程是指,要將變量設(shè)置為一個抽象類或接口數(shù)據(jù)類型的實例,而不是一個具體實現(xiàn)的實例。例如父類的一個改變會逐級向下傳遞給子類實現(xiàn),這可能會影響子類使用的某個算法。 設(shè)計模式 設(shè)計模式基本原則 設(shè)計原則 ① : 按接口而不是按實現(xiàn)來編程 按接口而不是按實現(xiàn)編程是指,要將變量設(shè)置為一個抽象類或接口數(shù)據(jù)類型的實例,而不是一...
摘要:又稱為多態(tài)性工廠模式或虛擬構(gòu)造子模式。簡單工廠模式簡單工廠模式簡單工廠模式又稱為靜態(tài)工廠方法模式,它屬于類創(chuàng)建型模式。多態(tài)性設(shè)計工廠方法模式之所以又被稱為多態(tài)工廠模式,是因為所有的具體工廠類都具有同一抽象父類。 點擊進入我的博客 2.1 簡單工廠模式 2.1.1 工廠模式的幾種形態(tài) 工廠模式主要用一下幾種形態(tài): 簡單工廠(Simple Factory):專門定義一個類來負責創(chuàng)建其他...
摘要:維基百科在軟件工程中,創(chuàng)建型設(shè)計模式是用于解決對象創(chuàng)建機制,嘗試在指定場景下使用合理的方式來創(chuàng)建對象的設(shè)計模式。維基百科說建造者模式是一種對象創(chuàng)建軟件設(shè)計模式,其目的是找到一種解決方案,以解決可伸縮構(gòu)造函數(shù)的反模式。 1.創(chuàng)建型設(shè)計模式2.結(jié)構(gòu)型設(shè)計模式3.行為型設(shè)計模式 創(chuàng)建型設(shè)計模式 簡而言之 創(chuàng)建型設(shè)計模式關(guān)注的是如何實例化一個或者一組相關(guān)的對象。 維基百科 在軟件工程中,創(chuàng)建型...
摘要:創(chuàng)建型模式主要有以下五種簡單工廠模式和工廠方法模式抽象工廠模式單例模式建造者模式原型模式在設(shè)計模式一書中將工廠模式分為兩類工廠方法模式與抽象工廠模式。 一、 設(shè)計模式(Design pattern)是什么 設(shè)計模式是一套被反復(fù)使用、多數(shù)人知曉、經(jīng)過分類編目的代碼設(shè)計的經(jīng)驗總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 二、 為什么會有設(shè)計模式 在軟件開發(fā)過...
閱讀 4042·2021-11-25 09:43
閱讀 2671·2021-11-18 13:11
閱讀 2364·2019-08-30 15:55
閱讀 3343·2019-08-26 11:58
閱讀 2900·2019-08-26 10:47
閱讀 2291·2019-08-26 10:20
閱讀 1344·2019-08-23 17:59
閱讀 3104·2019-08-23 15:54