一、基本概述
下面列出咖啡、茶的沖泡方法。
1.咖啡沖泡方法
(1) 把水煮沸
(2) 用沸水沖泡咖啡
(3) 把咖啡倒進杯子
(4) 家牛奶和糖
2.茶的沖泡方法
(1) 把水煮沸
(2) 用沸水浸泡茶葉
(3) 把茶倒進杯子
(4) 加檸檬
在使用**來完成這些方法時,我們一般想到的建立2個類(咖啡、茶類)來單獨實現這四個步驟。或者更好點是建立乙個飲料父類來共享第一步與第三步,然後繼承父類實現各自飲料的第二步與第四步。那麼還有更好一點的方式來處理上面的問題嗎?有,可以使用模版方法模式。
二、詳細說明
1.模版方法模式:在乙個方法中定義乙個演算法的骨架,而將一些步驟延遲到子類中。模版方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟。
這個模式是用來建立乙個演算法的模版。什麼是模版?如你所見,模版就是乙個方法。更具體地說,這個方法將演算法定義成一組步驟,其中的任何步驟都可以是抽象的,有子類負責實現。這可以確保演算法的結構保持不變,同時由子類提供部分實現。
鉤子是一種被宣告在抽象類中的方法,但只有空的或者預設的實現,鉤子的存在,可以讓子類有能力對演算法的不同點進行掛鉤。要不要掛鉤,由子類自行決定。
問:當我建立乙個模版方法時,怎麼才能知道什麼時候該使用抽象方法,什麼時候使用鉤子呢?
答:當你的子類「必須」提供演算法中某個方法或步驟的實現時,就使用抽象方法。如果演算法的這個部分是可選的,就用鉤子。如果是鉤子的話,子類可以選擇實現這個鉤子,但並不強制這麼做。
問:使用鉤子真正的目的是什麼?
答:鉤子有幾種用法。鉤子可以讓子類實現演算法中可選的部分,或者在鉤子對於子類的實現並不重要的時候,子類可以對此鉤子置之不理。鉤子的另乙個用法,是讓子類能夠有機會對模版方法中某些即將發生的步驟作出反應。鉤子也可以讓子類有能力為其抽象類作一些決定。
如在asp.net mvc框架中,你建立乙個控制器,預設都是繼承controller類,而controller類中就有鉤子,如onactionexecuted、onactionexecuting、onresultexecuted、onresultexecuting等,這些鉤子能夠在你的控制器中進行實現,以便控制或加工對請求的動作與返回的執行。
2.設計原則:好萊塢原則:別呼叫(打**給)我們,我們會呼叫(打**給)你。
好萊塢原則可以給我們一種防止「依賴腐敗」的方法。當高層元件依賴底層元件,而底層元件又依賴高層元件,而高層元件又依賴邊側元件,而邊側元件有依賴底層元件時,依賴腐敗就發生了。在這種情況下,沒有人可以輕易地搞懂系統是如何設計的。
在好萊塢原則之下,我們允許底層元件將自己掛鉤到系統上,但是高層元件會決定什麼時候和怎樣使用這些底層元件。換句話說,高層元件對待底層元件的方式是「別呼叫我們,我們會呼叫你」。
好萊塢原則和模版方法之間的連線其實還算明顯:當我們設計模版方法模式時,我們告訴子類,「不要呼叫我們,我們會呼叫你」。
問:底層元件不可以呼叫高層元件中的方法嗎?
答:並不盡然,事實上,底層元件在結束時,常常會呼叫從超類中繼承來的方法。我們所要做的是,避免讓高層和底層元件之間有明顯的環狀依賴。
模版方法模式是乙個很常見的模式,到處都是。儘管如此,你必須擁有一雙銳利的眼鏡,因為模版方法有許多實現,而它們看起來並不一定和書上所說的設計一致。
這個模式很常見是因為對建立框架來說,這個模式好用。有框架控制如何做事情,而由你(使用這個框架的人)指定框架演算法中每個步驟的細節。
如在c#陣列中,有array類提供乙個sort()方法用來排序,該方法有2個引數(乙個是陣列,乙個是icomparer 介面),sort方法提供了排序演算法,實現icomparer 介面的引數提供了陣列元素怎麼進行比較大小。
問:這真的是乙個模版方法模式嗎?
答:我們都知道,荒野中的模式並非總是如同教科書例子一般地中規中矩,為了符合當前的環境和實現的約束,它們總是要被適當地修改。這個array類的sort()方法的設計者受到一些約束,通常我們無法設計乙個類繼承c#陣列,而sort()方法希望能夠適用於所有的陣列(每個陣列都是不同的類)。所以它們定義了乙個靜態方法,而由被排序的物件內的每個元素自行提供比較大小的演算法部分。所以,這雖然不是教科書上的模版方法,但它的實現仍然符合模版方法模式的精神。再者,由於不需要繼承陣列可以使用這個演算法,這樣使得排序變得更有彈性、更有用。
4.總結:
1.好萊塢原則告訴我們,將決策權放在高層模組中,以便決定如何以及何時呼叫底層模組。
2.你將咋真實世界**中看到模版方法模式的許多變體,不要期待它們全都是一眼就可以被你認出的。
3.策略模式和模版方法模式都封裝演算法,乙個用組合,乙個用繼承。
4.工廠方法是模版方法的一種特殊版本。
三、**列表
publicview codeabstract
class
caffeinebeverage
protected
abstract
void
brew();
protected
abstract
void
addcondiments();
private
void
boilwater()
private
void
pourincup()
protected
virtual
void
hook()
}public
class
coffee:caffeinebeverage
protected
override
void
addcondiments()
}public
class
tea : caffeinebeverage
protected
override
void
addcondiments()
}
---------以上內容根據《head first design mode》進行整理
模版方法模式
模版方法模式 定義乙個操作中的演算法的骨架,而將一些步驟延遲到子類中,模版方法使得子類可以不改變乙個演算法的結果即可重定義該演算法的某些特定步驟。比如說 要輸入乙個excel檔案,然後需要對該檔案內容進行校驗,校驗完成之後 插入資料庫。演算法的步驟就是 校驗 落庫 但是不同的檔案,裡面的資料不同,比...
模版方法模式
定義 定義乙個操作中演算法的框架,而將一些步驟延遲到子類中,使得子類可以不改變演算法的結構即可重定義該 演算法中的某些特定步驟。型別 行為類模式 類圖 1.7 template method pattern 事實上,模版方法是程式設計中乙個經常用到的模式。先來看乙個例子,某日,程式設計師a拿到乙個任...
模版方法模式
1 模版方法模式 定義乙個操作中演算法的顧家,而將一些步驟延遲到子類中。模版方法是的子類可以不改變乙個演算法的結構即可從定義乙個演算法。2 當我們要完成某一細節層次一致的乙個過程或者系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,我們通常考慮用模版方法模式來處理。3 模版方法是通過把不變行為...