模板方法-設計模式

  • 2019 年 11 月 6 日
  • 筆記

在日常的工作生活中,有這些場景:(還有其他生活場景)

  1. 去銀行辦理業務一般會經過四個流程:取號、排隊、辦理業務以及辦理完業務後對工作人員進行評分等流程,其中取號、排隊和對銀行工作人員進行評分的業務對每個顧客都是同樣的,可以在父類中實現;但是辦理的業務每個人是不同的,取款、存款或者轉賬等,個人的具體業務可以在子類中實現。
  2. 一個人每天起床、吃飯、做事及睡覺等,其中做事情因為每個人不同而異,因此我們可以將起床,吃飯,以及睡覺定義為父類,做事定義為子類等
  3. 簡歷模板,論文模板,word模板等都可以定義為父類,每個人簡歷,論文,word模板又不同,可以定義為子類。

以下介紹模板方法模式將解決上述問題。

一 定義

模板方法(Template Method)模式定義為:定義了一個操作中的算法骨架,而將算法的部分步驟延遲到子類,使得子類可以不改變該算法結構的情況下重新定義該算法的某些特定的步驟。是一種類行為型模式。

 

二 特點

模板方法模式的優缺點如下

優點

  1. 封裝不變部分,擴展可變部分。不變部分的算法封裝到父類中去實現,而把可變部分算法由子類去繼承實現,便於子類擴展。
  2. 父類中提取了公共的代碼部分,便於代碼復用。
  3. 部分的方法是由子類實現,子類拓展相應的功能,符合了開閉原則。

缺點

  1. 對每個不同的實現都需要一個子類,導致了類的個數增加,系統變得龐大。
  2. 父類中的抽象方法是由子類實現,子類執行的結果也會影響到父類,提高了代碼的閱讀難度。

 

三 模板結構和實現

模板方法模式需要注意具體子類與抽象類之間的協議工作,它用到了虛函數的多態性技術以及反向控制技術。現在介紹其基本結構。

3.1 模板的結構

模板方法模式主要包含以下角色。

3.1.1 抽象類(abstract class)定義了算法的骨架,由一個模板方法和若干個基本的方法來構成。

  1. 模板方法:定義算法的骨架,按某種順序調用包含的方法。
  2. 基本方法:是算法中的一個步驟,包含了以下幾種類型。
  • 抽象方法:在抽象類中申明,是由子類去實現。
  • 具體方法:在抽象類中已經實現,在具體子類中去繼承或者重寫
  • 鉤子方法:在抽象類已經實現,包括用於判斷的邏輯以及需要子類重寫的空方法兩種。

拓展:釘子方法

就是在抽象類中定義一個方法,默認不做任何事,子類可以根據實際情況要不要覆蓋它,從而改變行為,該方法稱為“鉤子”。

3.1.2 具體子類(concrete class)實現抽象類中所定義的抽象方法和鉤子方法。

結構圖如下:

 

3.2 模板的具體實現

模板方法的模式代碼如下

package templateMethod;  public class TemplateMethodPattern  {      public static void main(String[] args)      {          AbstractClass tm=new ConcreteClass();          tm.TemplateMethod();      }  }  //抽象類  abstract class AbstractClass  {      public void TemplateMethod() //模板方法      {          SpecificMethod();          abstractMethod1();          abstractMethod2();      }      public void SpecificMethod() //具體方法      {          System.out.println("抽象類中的具體方法被調用...");      }      public abstract void abstractMethod1(); //抽象方法1      public abstract void abstractMethod2(); //抽象方法2  }  //具體子類  class ConcreteClass extends AbstractClass  {      public void abstractMethod1()      {          System.out.println("抽象方法1的實現被調用...");      }      public void abstractMethod2()      {          System.out.println("抽象方法2的實現被調用...");      }  }

程序的運行的結果如下

抽象類中的具體方法被調用...  抽象方法1的實現被調用...  抽象方法2的實現被調用...

 

四 應用實例

示例

模擬製作咖啡店家接受訂單的過程。父類Coffee定義了公共的方法,如研磨咖啡豆,同時定義了可變的部分。但是呢,有的消費者不喜歡加奶,有的不喜歡加糖,所以定義了鉤子方法isAddMilk和isAddSugar判斷是否要加奶加糖,而子類根據實際需要判斷是否要加奶加糖。

Coffee(父類-抽象)

public abstract class Coffee {      boolean addSugarFlag = false;      boolean addMilkFlag = false;      public boolean isAddMilkFlag() {          return addMilkFlag;      }      public boolean isAddSugarFlag() {          return addSugarFlag;      }      Coffee prepareHotWater(){          System.out.println("準備熱水");          return this;      }      Coffee grindCoffeeBean(){          System.out.println("研磨咖啡豆");          return this;      }      void addSugar(){          System.out.println("加糖");      }      void addMilk(){          System.out.println("加奶");      }      Coffee make(String coffeeName){          Coffee coffee = prepareHotWater().grindCoffeeBean();          if(isAddMilkFlag()){              coffee.addMilk();          }          if(isAddSugarFlag()){              coffee.addSugar();          }          System.out.println("製作完成!這是一杯"                  + (isAddSugarFlag() ? "" : "不加") + "糖,"                  + (isAddMilkFlag() ? "" : "不加") + ""                  + "" + coffeeName);          return coffee;      }  }

 Cap類和Latte類

public class Cap extends Coffee {      String coffeeName = "卡布奇諾";      Coffee make(){          return super.make(this.coffeeName);      }      @Override      public boolean isAddSugarFlag() {          return true;      }  }    public class Latte extends Coffee {      String coffeeName = "拿鐵";      Coffee make(){          return super.make(this.coffeeName);      }      @Override      public boolean isAddMilkFlag() {          return true;      }      @Override      public boolean isAddSugarFlag() {          return true;      }  }

Test類

public class Test {      public static void main(String[] args) {          System.out.println("******  下訂單:一杯加糖,不加奶的熱卡布奇諾  ******");          Cap cappuccino = new Cap();          cappuccino.make();          System.out.println("******  下訂單:一杯加糖,加奶的熱拿鐵  ******");          Latte latte = new Latte();          latte.make();      }  }

輸出結果

******  下訂單:一杯加糖,不加奶的熱卡布奇諾  ******  準備熱水  研磨咖啡豆  加糖  製作完成!這是一杯加糖,不加奶的卡布奇諾  ******  下訂單:一杯加糖,加奶的熱拿鐵  ******  準備熱水

 

五 總結

開發過程中,使用模板方法模式很方便將共有的代碼提取出來,能夠降低代碼的冗餘,提高了開發的效率,在開發中應該100%會被用到,或者用到了你卻不知道。希望通過本篇博客,大家能夠加深對模板方法模式的理解。下一次,我們將講述設計模式-策略模式,歡迎關注,會實時更新博客!!!