1、 基本概述算法
下面列出咖啡、茶的沖泡方法。數組
1.咖啡沖泡方法框架
(1) 把水煮沸ide
(2) 用沸水沖泡咖啡spa
(3) 把咖啡倒進杯子.net
(4) 家牛奶和糖設計
2.茶的沖泡方法code
(1) 把水煮沸對象
(2) 用沸水浸泡茶葉blog
(3) 把茶倒進杯子
(4) 加檸檬
在使用代碼來完成這些方法時,咱們通常想到的建立2個類(咖啡、茶類)來單獨實現這四個步驟。或者更好點是建立一個飲料父類來共享第一步與第三步,而後繼承父類實現各自飲料的第二步與第四步。那麼還有更好一點的方式來處理上面的問題嗎?有,可使用模版方法模式。
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.工廠方法是模版方法的一種特殊版本。
3、代碼列表
public abstract class CaffeineBeverage { public void PrepareRecipe() { BoilWater(); Brew(); PourInCup(); AddCondiments(); Hook(); } protected abstract void Brew(); protected abstract void AddCondiments(); private void BoilWater() { Console.WriteLine("Boiling water"); } private void PourInCup() { Console.WriteLine("Pouring into cup"); } protected virtual void Hook() { } } public class Coffee:CaffeineBeverage { protected override void Brew() { Console.WriteLine("沖泡咖啡"); } protected override void AddCondiments() { } } public class Tea : CaffeineBeverage { protected override void Brew() { Console.WriteLine("浸泡茶"); } protected override void AddCondiments() { Console.WriteLine("加檸檬"); } }
---------以上內容根據《Head First Design Mode》進行整理