(1)什麼是平行的類層次結構呢?
簡單點說,假如有兩個類層次結構,其中乙個類層次中的每個類在另乙個類層次中都有乙個對應的類的結構,就被稱為平行的類層次結構。
舉個例子來說,硬碟物件有很多種,如分成台式電腦硬碟和筆記本硬碟,在台式電腦硬碟的具體實現上面,又有希捷、西數等不同品牌的實現,同樣在筆記本硬碟上,也有希捷、日立、ibm等不同品牌的實現;硬碟物件具有自己的行為,如硬碟能儲存資料,也能從硬碟上獲取資料,不同的硬碟物件對應的行為物件是不一樣的,因為不同的硬碟物件,它的行為的實現方式是不一樣的。如果把硬碟物件和硬碟物件的行為分開描述,那麼就構成了如圖10所示的結構:
圖10 平行的類層次結構示意圖
硬碟物件是乙個類層次,硬碟的行為這邊也是乙個類層次,而且兩個類層次中的類是對應的。台式電腦西捷硬碟物件就對應著硬碟行為裡面的台式電腦西捷硬碟的行為;筆記本ibm硬碟就對應著筆記本ibm硬碟的行為,這就是一種典型的平行的類層次結構。
這種平行的類層次結構用來幹什麼呢?主要用來把乙個類層次中的某些行為分離出來,讓類層次中的類把原本屬於自己的職責,委託給分離出來的類去實現,從而使得類層次本身變得更簡單,更容易擴充套件和復用。
一般來講,分離出去的這些類的行為,會對應著類層次結構來組織,從而形成乙個新的類層次結構,相當於原來物件的行為的這麼乙個類層次結構,而這個層次結構和原來的類層次結構是存在對應關係的,因此被稱為平行的類層次結構。
(2)工廠方法模式跟平行的類層次結構有何關係呢?
可以使用工廠方法模式來連線平行的類層次。
看上面的示例圖10,在每個硬碟物件裡面,都有乙個工廠方法createhdoperate,通過這個工廠方法,客戶端就可以獲取乙個跟硬碟物件相對應的行為物件。在硬碟物件的子類裡面,會覆蓋父類的工廠方法createhdoperate,以提供跟自身相對應的行為物件,從而自然的把兩個平行的類層次連線起來使用。
所謂引數化工廠方法指的就是:通過給工廠方法傳遞引數,讓工廠方法根據引數的不同來建立不同的產品物件,這種情況就被稱為引數化工廠方法。當然工廠方法建立的不同的產品必須是同乙個product型別的。
來改造前面的示例,現在有乙個工廠方法來建立exportfileapi這個產品的物件,但是exportfileapi介面的具體實現很多,為了方便建立的選擇,直接從客戶端傳入乙個引數,這樣在需要建立exportfileapi物件的時候,就把這個引數傳遞給工廠方法,讓工廠方法來例項化具體的exportfileapi實現物件。
還是看看**示例會比較清楚。
(1)先來看product的介面,就是exportfileapi介面,跟前面的示例沒有任何變化,為了方便大家檢視,這裡重複一下,示例**如下:
/** * 匯出的檔案物件的介面
*/ public
inte***ce exportfileapi
public
class exporttxtfile implements exportfileapi
} public
class exportdb implements exportfileapi }
(3)接下來該看看exportoperate類了,這個類的變化大致如下:
看看**吧,示例**如下:
/** * 實現匯出資料的業務功能物件*/
public
class exportoperate
/*** 工廠方法,建立匯出的檔案物件的介面物件
* @param type 使用者選擇的匯出型別
* @return 匯出的檔案物件的介面物件
*/ protected exportfileapi factorymethod(int type)else if(type==2)
return api;
} }
(4)此時的客戶端,非常簡單,直接使用exportoperate類,示例**如下:
public
class client }
測試看看,然後修改一下客戶端的引數,體會一下通過引數來選擇具體的匯出實現的過程。這是一種很常見的引數化工廠方法的實現方式,但是也還是有把引數化工廠方法實現成為抽象的,這點要注意,並不是說引數化工廠方法就不能實現成為抽象類了。只是一般情況下,引數化工廠方法,在父類都會提供預設的實現。
(5)擴充套件新的實現
使用引數化工廠方法,擴充套件起來會非常容易,已有的**都不會改變,只要新加入乙個子類來提供新的工廠方法實現,然後在客戶端使用這個新的子類即可。
這種實現方式還有乙個有意思的功能,就是子類可以選擇性覆蓋,不想覆蓋的功能還可以返回去讓父類來實現,很有意思。
先擴充套件乙個匯出成xml檔案的實現,試試看,示例**如下:
/** * 匯出成xml檔案的物件
*/ public
class exportxml implements exportfileapi }
然後擴充套件exportoperate類,來加入新的實現,示例**如下:
/** * 擴充套件exportoperate物件,加入可以匯出xml檔案
*/ public
class exportoperate2 extends exportoperateelse
return api;
} }
看看此時的客戶端,也非常簡單,只是在變換傳入的引數,示例**如下:
public
class client }
對應的測試結果如下:
匯出資料test1到文字檔案
匯出資料test2到資料庫備份檔案
匯出資料test3到xml檔案
通過上面的示例,好好體會一下引數化工廠方法的實現和帶來的好處。
1:工廠方法模式的本質
工廠方法模式的本質:延遲到子類來選擇實現。
仔細體會前面的示例,你會發現,工廠方法模式中的工廠方法,在真正實現的時候,一般是先選擇具體使用哪乙個具體的產品實現物件,然後建立這個具體產品物件的示例,然後就可以返回去了。也就是說,工廠方法本身並不會去實現產品介面,具體的產品實現是已經寫好了的,工廠方法只要去選擇實現就好了。
有些朋友可能會說,這不是跟簡單工廠一樣嗎?
確實從本質上講,它們是非常類似的,具體實現上都是在「選擇實現」。但是也存在不同點,簡單工廠是直接在工廠類裡面進行「選擇實現」;而工廠方法會把這個工作延遲到子類來實現,工廠類裡面使用工廠方法的地方是依賴於抽象而不是具體的實現,從而使得系統更加靈活,具有更好的可維護性和可擴充套件性。
其實如果把工廠模式中的creator退化一下,只提供工廠方法,而且這些工廠方法還都提供預設的實現,那不就變成了簡單工廠了嗎?比如把剛才示範引數化工廠方法的例子**拿過來再簡化一下,你就能看出來,寫得跟簡單工廠是差不多的,示例**如下:
看完上述**,會體會到簡單工廠和工廠方法模式是有很大相似性的了吧,從某個角度來講,可以認為簡單工廠就是工廠方法模式的一種特例,因此它們的本質是類似的,也就不足為奇了。
2:對設計原則的體現
工廠方法模式很好的體現了「依賴倒置原則」。
依賴倒置原則告訴我們「要依賴抽象,不要依賴於具體類」,簡單點說就是:不能讓高層元件依賴於低層元件,而且不管高層元件還是低層元件,都應該依賴於抽象。
比如前面的示例,實現客戶端請求操作的exportoperate就是高層元件;而具體實現資料匯出的物件就是低層元件,比如exporttxtfile、exportdb;而exportfileapi介面就相當於是那個抽象。
對於exportoperate來說,它不關心具體的實現方式,它只是「面向介面程式設計」;對於具體的實現來說,它只關心自己「如何實現介面」所要求的功能。
那麼倒置的是什麼呢?倒置的是這個介面的「所有權」。事實上,exportfileapi介面中定義的功能,都是由高層元件exportoperate來提出的要求,也就是說介面中的功能,是高層元件需要的功能。但是高層元件只是提出要求,並不關心如何實現,而低層元件,就是來真正實現高層元件所要求的介面功能的。因此看起來,低層實現的介面的所有權並不在底層元件手中,而是倒置到高層元件去了。
3:何時選用工廠方法模式
建議在如下情況中,選用工廠方法模式:
在大家的鼓勵和支援下,《研磨設計模式》一書終於製作完成,即將與大家見面,現已進行預售,喜愛的朋友可以前往選購。
,謝謝大家的支援!
要是覺得這本書有用,記得在**說幾句好話啊,寫書真的很辛苦,希望大家支援_^_
工廠方法模式結束,謝謝**!
研磨設計模式之工廠方法模式 2
用來解決上述問題的乙個合理的解決方案就是工廠方法模式。那麼什麼是工廠方法模式呢?1 工廠方法模式定義 定義乙個用於建立物件的介面,讓子類決定例項化哪乙個類,factory method使乙個類的例項化延遲到其子類。2 應用工廠方法模式來解決的思路 仔細分析上面的問題,事實上在實現匯出資料的業務功能物...
研磨設計模式之工廠方法模式 3
1 模式的功能 工廠方法的主要功能是讓父類在不知道具體實現的情況下,完成自身的功能呼叫,而具體的實現延遲到子類來實現。這樣在設計的時候,不用去考慮具體的實現,需要某個物件,把它通過工廠方法返回就好了,在使用這些物件實現功能的時候還是通過介面來操作,這非常類似於ioc di的思想,這個在後面給大家稍詳...
研磨設計模式之工廠方法模式 2
size medium 2 解決方案 size 2.1 工廠方法模式來解決 用來解決上述問題的乙個合理的解決方案就是工廠方法模式。那麼什麼是工廠方法模式呢?1 工廠方法模式定義 定義乙個用於建立物件的介面,讓子類決定例項化哪乙個類,factory method使乙個類的例項化延遲到其子類。2 應用工...