模版方法模式

来源:http://www.cnblogs.com/zwt-blog/archive/2017/06/13/7003375.html
-Advertisement-
Play Games

一、 基本概述 下麵列出咖啡、茶的沖泡方法。 1.咖啡沖泡方法 (1) 把水煮沸 (2) 用沸水沖泡咖啡 (3) 把咖啡倒進杯子 (4) 家牛奶和糖 2.茶的沖泡方法 (1) 把水煮沸 (2) 用沸水浸泡茶葉 (3) 把茶倒進杯子 (4) 加檸檬 在使用代碼來完成這些方法時,我們一般想到的創建2個類 ...


一、   基本概述

下麵列出咖啡、茶的沖泡方法。

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.工廠方法是模版方法的一種特殊版本。

三、代碼列表

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("加檸檬");
    }
}
View Code

---------以上內容根據《Head First Design Mode》進行整理


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 操作系統: CentOS 6.9_x64 go語言版本: 1.8.3 問題描述 現有一個tcp客戶端程式,需定期從伺服器取數據,但由於種種原因(網路不穩定等)需要自動重連。 測試伺服器示例代碼: /* tcp server for test E-Mail : [email protected] ...
  • Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. ...
  • 用scoket 寫一個簡版的ssh 服務端: 客戶端: 在win10下,recv(1024)的時候ipconfig指令 會出錯,其它的命令暫時沒發現 ...
  • Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the hist... ...
  • 今天這裡寫一個演算法 給你一組數字,然後求出這組數中出現次數最多的數以及出現最多的次數。 下麵就直接上代碼了,主要的註釋都會在裡面說明。 通過這個演算法,可以讓我們更好地理解map集合,代碼中我寫了兩種遍歷map集合的方法,雖然說掌握一種就可以了,但是畢竟技多不壓身,多學點東西還是很好的,尤其是第二種, ...
  • 博主今天去了一個java的實習面試,發現有好多java最基礎的數據結構對於博主來說反而感到陌生,在面試官問一些常見的例如HashMap這樣的數據結構,博主能回答的頭頭是道,但是在問到Array和ArrayList的區別和聯繫之後,卻讓博主一臉懵。好吧,不多說,現在特此整理。 首先, Array是ja ...
  • 學習的最好途徑就是看書 "學習的最好途徑就是看書",這是我自己學習並且小有了一定的積累之後的第一體會。個人認為看書有兩點好處: 1、能出版出來的書一定是經過反覆的思考、雕琢和審核的,因此從專業性的角度來說,一本好書的價值遠超其他資料 2、對著書上的代碼自己敲的時候方便 "看完書之後再次提升自我的最好 ...
  • 在JavaEE開發中,在把配置文件中的數據或用戶表單提交上來的數據,封裝在相應JavaBean的對象的對應屬性中時:在實際開發中,使用第三方法工具包BeanUtils(commons-beanutils-xxx.jar 依賴於commons-logging-xx.jar)。 如博主在JavaWeb工 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...