設計模式(九): 從醋溜土豆絲和清炒苦瓜中來學習"模板方法模式"(Template Method Pattern)

来源:http://www.cnblogs.com/ludashi/archive/2016/05/04/5420660.html
-Advertisement-
Play Games

今天是五.四青年節,祝大家節日快樂。看著今天這標題就有食欲,夏天到了,醋溜土豆絲和清炒苦瓜適合夏天吃,好吃不上火。這兩道菜大部分人都應該吃過,特別是醋溜土豆絲,作為“魯菜”的代表作之一更是為大眾所熟知,醋溜土豆絲,好吃不上火。清炒苦瓜這道菜好啊,更是夏天必備之良菜,其功效在此就不做過多贅述了。言歸正 ...


今天是五.四青年節,祝大家節日快樂。看著今天這標題就有食欲,夏天到了,醋溜土豆絲和清炒苦瓜適合夏天吃,好吃不上火。這兩道菜大部分人都應該吃過,特別是醋溜土豆絲,作為“魯菜”的代表作之一更是為大眾所熟知,醋溜土豆絲,好吃不上火。清炒苦瓜這道菜好啊,更是夏天必備之良菜,其功效在此就不做過多贅述了。言歸正傳,上篇博客我們從“小弟”中學習了“外觀模式”,我們也把“外觀模式”戲稱為“小弟模式”。今天我們要從醋溜土豆絲和清炒苦瓜的製作過程中來學習一下我們今天博客的主題“模板方法模式”(Template Method Pattern)。

說到模板方法模式,如果你看過之前發表的重構相關的博客的話,應該對模板方法模式並不陌生。在代碼重構(五):繼承關係重構規則這篇博客中第三部分,其實是使用的“模板方法模式”進行重構的,在重構規則裡邊我們稱之為“Form Template Method (構造模板函數)”,這個模板函數就是我們本篇博客中的模板方法。今天我們要從另一個角度來看一下“模板方法模式”,並從“醋溜土豆絲”和“清炒苦瓜”的製作實例中來學習一下“模板方法模式”。在本篇博客中,你不僅是一位Programer,還是一位Cook。

老規矩,在博客的開頭,我們先給出“模板方法模式”的定義。如果你是小白,定義看不懂沒關係,因為定義一般都比較難理解。你可以看完下方的具體實例後在回頭看這個定義即可。模板方法的定義如下:

模板方法模式:在一個方法中定義了一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟。

 

一、開始炒菜

接下來我們將要開始製作我們的醋溜土豆絲和清炒苦瓜這兩道菜,當然在本篇博客的第一部分我們不會使用我們的模板方法來炒菜的。我們在該部分先給出常規的做菜的方法,然後我們會對其分析,最終會使用我們的“模板方法模式”來進行炒菜。當然在此我們不是真的用鍋炒菜了,而是用我們的代碼來炒菜,走起。

1.炒一個醋溜土豆絲

接下來我們要炒一個醋溜土豆絲,醋溜土豆絲好吃,做起來又簡單。還是那句話,醋溜土豆絲,好吃不上火。因為炒“醋溜土豆絲”我們是在一個類中完成的,所以在此就不畫類圖了,等下發使用模板方法模式後,在給出相應的類圖。下方的FryShreddedPotatoes類就是我們做“醋溜土豆絲”的類。其中給出了做醋溜土豆絲的一系列的步驟,並且在fryShreddedPotatoes()函數中對這一系列的函數進行了組合。

   

上面完成的這個類,我們就可以將上述這個類進行實例化並調用fryShreddedPotatoes()來炒一盤醋溜土豆絲了。下方我們就將FryShreddedPotatoes進行實例化,然後炒了一盤醋溜土豆絲。

   

   

 

 

2、來一盤“清炒苦瓜”

上面土豆絲炒完了,已出鍋。接下來我們還要來一盤“清炒苦瓜”,當然“清炒苦瓜”的做法和上面“醋溜土豆絲”差不過,不過有些步驟還是不同的。當然你在炒苦瓜的時候不能放醋了,還有在炒苦瓜的時候你放的是苦瓜片而不是土豆絲了,這些都是不同的。當然兩者的菜名也不一樣呢。下方這個類就是我們“清炒苦瓜”的類,你可以將該類進行實例化然後去做一盤屬於你的清炒苦瓜。大體上一看,下方的代碼與上面我們醋溜土豆絲的類的步驟差不多,但是具體細節,以及一些步驟所調用的方法所不同。下方就是我們清炒苦瓜的類,如下所示:

    

接著就是來實例化上面“清炒苦瓜”的類,然後來一盤清炒苦瓜。下方是我們創建的上面的類的對象,然後去調用炒苦瓜的方法。下方是調用方式和輸出結果,經過下方的過程,我們就可以出鍋一盤清炒苦瓜了,如下所示:

    

    

 

二、使用“模板方法”來炒菜

在上面兩種炒菜的方法中,我們不難看出炒醋溜土豆絲和清炒苦瓜中的類中有好多重覆的代碼。在我們重構系列中的博客中我們已經提到切記重覆代碼,所以我們要對上面的兩個類進行代碼的重構,而重構的方式就是使用“模板方法模式”來進行重構。本質上就是將變的部分與不變的部分進行分離,在該實例中變的部分就是某些步驟的具體細節,而不變的是執行的步驟和部分步驟中的內容。

在該炒菜實例中整個炒菜的流程是不變的,該流程中的一些步驟也是不變的。變化的就是報菜名方法中所報的菜名不同,然後是所炒的菜不同,一個炒的是土豆絲一個炒的是苦瓜,最後是加的調料不同。這樣一分析,我們可以將不變的方法放到父類中,將炒菜這個不變的步驟封裝成“模板方法”,具體不變的某些步驟(比如放油等)可以放在延展中實現。該部分的代碼結構些微的有些複雜,所以我們會給出相應的類圖。

 

1.重構後的類圖如下(使用了“模板方法模式”)

首先我們會給出重構後的類圖,使用“模板方法模式”重構後的類圖如下所示。 FryVegetablesType是我們創建的炒菜協議,其中定義了“醋溜土豆絲”和“清炒苦瓜”所有的方法,不過我們對兩者不同的方法進行了重新命名,讓其統一。因為兩者不同的方法所實現的東西大體一致,比如之前清炒苦瓜中的放苦瓜的方法putBitterGourd(),我們重命名成了“放蔬菜”的putVegetables()方法。putVegetables()方法用於“醋溜土豆絲”中也是可以的,因為putVegetables()在“清炒苦瓜”中放的是苦瓜,在炒土豆絲中放的是土豆絲。

在FryVegetablesType協議的延展中,我們給出了相同的預設實現,比如模板方法(fry())、放油(putSomeOil())、放蔥花(putSomeGreenOnion())、出鍋(outOfThePan())等方法。在炒這兩個菜時延展中的方法是不變的。而我們炒土豆絲和炒苦瓜中實現的方法是兩者不同的地方,類圖如下:

   

 

2.炒菜介面與介面延展代碼實現

根據上述的類圖,我們可以給出炒菜介面以及介面延展的代碼實現。接下來要做的事情就是將不變的部分提取到介面和介面的延展中,下方就是我們提取的炒菜的介面FryVegetablesType以及該介面對應的延展。FryVegetablesType協議中給出了模板方法fry(),以及炒菜的步驟(也就是炒菜的演算法)。在該介面的延展中,模板方法fry()的預設實現調用和這些步驟,並且給出了一些不變的步驟的實現。具體代碼如下所示:

   

 

3.“醋溜土豆絲”和“清炒苦瓜”的具體實現

下方代碼段是醋溜土豆絲和清炒苦瓜在模板方法模式中的代碼實現。從下方代碼我們不難看出,兩者都遵循了FryVegetablesType協議,並且擁有該協議的預設擴展。我們知道預設擴展中的代碼類似於抽象類的預設實現,為子類所共有,所以下方兩個類只給出了不同的步驟。比如在醋溜土豆絲中放的作料是鹽和醋,而在清炒苦瓜中放的作料是鹽。當然兩個子類中其他實現的兩個方法也是不同之處。無論子類怎麼給出預設實現的步驟,我們在預設延展中給出的模板方法是不變的,也就是炒菜的具體步驟是不變的。這就是模板方法模式,模板方法不關心每個步驟的具體細節,只關心步驟執行的順序,這就是所謂的模板方法是對演算法的封裝,而不是對具體計算細節的封裝。

使用模板方法的一個顯而易見的好處就是減少了代碼冗餘,將變化的部分與不變的部分進行了分離。在該示例中就是將不變的部分放在了協議的預設延展中,將變化的部分放在了子類中。這就是“模板方法模式”。

 

4、“模板方法模式”的測試用例

接下來我們要對上述的示例進行測試,下方就是我們模板方法的測試用例,其實下方的測試用例與之前沒有使用模板方法時的測試用例類似,只是炒菜調用的方法有所不同。雖然調用的方法有些差異,此處的差異僅僅是函數名稱的差異,該函數所做的事情沒有變化。下方就是我們重構後的代碼的測試用例以及運行結果。從結果中看出,與我們之前沒有使用模板方法的測試用例的輸出結果一致。這就是我們之前在“重構”系列博客中經常提到的改變代碼內部的結構,而不改變代碼對外調用的介面。

    

 

本篇博客與之前我們類重構中的“構建模板方法”的部分較為類似,都是介紹的模板方法模式。而在前面我們是從重構的角度來使用模板方法模式的,而今天的博客的主題不是重構而是我們的“模板方法模式”。由於篇幅有限,我們的今天的博客就先到這兒,後面還會繼續更新其他Swift版的設計模式。

今天博客中的代碼在github上的分享地址為:https://github.com/lizelu/DesignPatterns-Swift 

 


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

-Advertisement-
Play Games
更多相關文章
  • 解釋器模式(Interpreter) 定義 解釋器模式(Interpreter),給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。 類圖 描述 Expression:抽象表達式,聲明一個所有的具體表達式都需要實現的抽象介面;這個介面主要是一個inter ...
  • 1.意圖 定義一個用於創建對象的介面,讓子類決定實例化哪一個類。Factory Method使一個類的實例化延遲到其子類。 2.動機 框架使用抽象類定義和維護對象之間的關係。這些對象的創建通常也由框架負責。 3.適用性 當一個類不知道它所必須創建的對象的類的時候。 當一個類希望由它的子類來指定它所創 ...
  • 主要利用工廠模式來實現了一個計算器,將加減乘除操作分離了開來,實現了低耦合的目標。 ...
  • 使用嵌套的 ILifetimeScope 解析服務 Autofac 被設計為跟蹤(track)和清理(dispose)資源。為確保資源被正確處理,務必將長時間運行的應用程式分成小的工作單元 (請求或事務),服務的解析應在工作單元級別的生命周期範圍中進行。為 asp.net 實現的每個請求一個生命周期 ...
  • 一、框架概述 1.1 框架的意義與作用: 所謂框架,就是把一些繁瑣的重覆性代碼封裝起來,使程式員在編碼中把更多的經歷放到業務需求的分析和理解上面。特點:封裝了很多細節,程式員在使用的時候會非常簡單。1.2 三大框架:Struts2,Hibernate,Spring1.3 如何學好框架由於框架中細節很 ...
  • 長久以來,伺服器端的高層架構大體被區分為對立的兩類:SOA(Service-oriented architecture)以及 AIO(All in one)。SOA 將一個完整的應用分割為相互獨立的服務,每個服務提供一個單一標準功能
  • 《Clean Code》是一本令人印象深刻的書,它將編碼當成寫作,強調代碼應當像文章一樣清晰準確而不是晦澀難懂。 同時作者給出了操作性很強的編碼建議: ...
  • 前言 這篇博客的目的是對項目中偶爾碰到的應用設計模式的代碼積累一下。 我認為針對於設計模式的學習,通過看書、看例子只能瞭解概念,而重要的是如何把概念應用到實際的項目開發中。 而且我想提醒大家的是,學習設計模式時,千萬不要拘泥於書上的內容,形成定式思維,這樣對於其他源碼理解會出現一層自然屏障,理解起來 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...