一個最簡單的設計模式-模板方法
阿新 • • 發佈:2019-07-15
《Head First設計模式》已經讀了不止一遍,但是始終沒有進行系統的進行總結。所以近期開始總結設計模式相關的知識,從模板方法模式開始,因為是一個我認為是最簡單的設計模式。(推薦視訊資源23個設計模式)
提出&解決問題
提出問題
實現製作咖啡功能。且製作咖啡需要四個步驟 :
- 燒水
- 沖泡咖啡
- 倒入杯中
- 加糖
程式碼實現
/** * 一杯加糖咖啡 * * @author Jann Lee * @date 2019-07-14 18:37 */ public class Coffee { /** * 製作一杯加糖咖啡 */ public void prepareRecipe() { boilWater(); steepTeaBag(); portInCup(); addLemon(); } /** * step1: 燒水 */ private void boilWater() { System.out.println("燒水..."); } /** * step2:沖泡咖啡 */ private void steepTeaBag() { System.out.println("沖泡咖啡..."); } /** * step3: 倒入杯中 */ private void portInCup() { System.out.println("倒入杯中..."); } /** * step4: 加糖 */ private void addLemon() { System.out.println("加糖..."); }
再次提出問題此時此刻我需要一杯檸檬茶呢?【燒水,沖泡茶包,倒入杯中,加檸檬】
這個問題當然很簡單,我們只需要如法炮製即可。
public class Tea { /** * 製作一杯檸檬茶 */ public void prepareRecipe(){ boilWater(); brewCoffeeGrinds(); portInCup(); addSugarAndMilk(); } /** * step1: 燒水 */ private void boilWater() { System.out.println("燒水..."); } /** * step2:沖泡咖啡 */ private void brewCoffeeGrinds() { System.out.println("沖泡茶包..."); } /** * step3: 倒入杯中 */ private void portInCup() { System.out.println("倒入杯中..."); } /** * step4: 加檸檬 */ private void addSugarAndMilk() { System.out.println("加入檸檬片..."); } }
思考
如果此時我們又需要一杯不加檸檬的茶,加奶的咖啡...,當然我們可以按照上面方式重新依次實現即可。但是如果你是一個有經驗的程式設計師,或者你學習過設計模式。你可能會發現以上功能實現的步驟/流程固定,當需求發生變化時,只有小部分步驟有所改變。
優化程式碼
根據面向物件程式的特點,既抽象,封裝,繼承,多型。我們可以對程式碼進行抽象,將公共程式碼提取到基類。我們將咖啡和茶抽象成咖啡因飲料,將其中相同的兩步,燒水和倒入杯中再父類中實現,將沖泡和新增調料延遲到子類。
- 定義一個基類
public abstract class CafeineBeverage { /** * 製作一杯咖啡因飲料 */ public void prepareRecipe() { boilWater(); brew(); portInCup(); addCondiments(); } /** * step1: 燒水 */ private void boilWater() { System.out.println("燒水..."); } /** * step2:沖泡 */ protected abstract void brew(); /** * step3: 入杯中 */ private void portInCup() { System.out.println("倒入杯中..."); } /** * step4: 加調料 */ protected abstract void addCondiments(); }
// 一杯加糖咖啡
public class CoffeeBeverage extends CafeineBeverage{
@Override
protected void brew() {
System.out.println("沖泡咖啡...");
}
@Override
protected void addCondiments() {
System.out.println("加糖...");
}
}
// 一杯檸檬茶
public class TeaBeverage extends CafeineBeverage {
@Override
protected void brew() {
System.out.println("沖泡茶包...");
}
@Override
protected void addCondiments() {
System.out.println("加檸檬...");
}
}
模板方法模式
如果按以上方式對程式碼進行了優化,其實就實現了模板方法模式。一下是模板方法模式相關概念。
動機
- 在軟體構建過程中,對於某一項任務,它常常有穩定的整體操作結構,但是各個子步驟卻有很多改變的需求,或者由於固有的原因(比如框架與應用之間的關係)而無法和任務的整體結構同時實現
- 如何在確定穩定的操作結構的前提下,來靈活應對各個子步驟的變化或者晚期實現需求?
定義
定義一個操作中演算法的骨架(穩定),而將一些步驟延遲(變化)到子類。Template Method使得子類可以不改變(複用)一個演算法的結構,即可重新定義(override)該演算法的特定步驟。
要點總結
- Template Method是一種非常基礎性的設計模式,在面向物件系統中,有著大量的應用。他用最簡潔的機制(抽象類的多型,為很多應用框架提供了靈活的擴充套件點,是程式碼複用方面最基本實現結構)
- 除了可以靈活應對子步驟的變化外,“不要呼叫我,讓我來呼叫你”的反向控制結構是Template Method的典型應用
- 在具體實現方面,被Template Method呼叫得虛方法可以有實現,也可以沒有實現(抽象方法),但一般推薦設定為protected方法
類圖:
個人部落格網站(正在建設中)