1. 程式人生 > >「補課」進行時:設計模式(3)——和做菜一樣簡單的模版方法模式

「補課」進行時:設計模式(3)——和做菜一樣簡單的模版方法模式

![](https://cdn.geekdigging.com/DesignPatterns/java_design_pattern.jpg) ## 1. 前文彙總 [「補課」進行時:設計模式系列](https://www.geekdigging.com/category/%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f/) ## 2. 做菜? 做菜大致需要幾個步驟? 1. 洗菜 2. 切菜 3. 起鍋燒油 4. 裝盤 剩下的就可以吃了,對吧~~~ ![](https://cdn.geekdigging.com/DesignPatterns/03/jugelizi.jpg) 現在,我們要做一個番茄炒蛋,就下面這貨: ![](https://cdn.geekdigging.com/DesignPatterns/03/fanqiechaodan.jpg) - 第一步:先把番茄洗乾淨去皮。 - 第二步:番茄切好,雞蛋打散。 - 第三步:起鍋燒油,一頓翻炒。 - 第四步:裝盤,大功告成。 這件事情我用程式實現下,先抽象一個做菜的模型: ```java public abstract class AbstractCook { /** * 做菜第一步就是先洗菜 */ public abstract void xicai(); /** * 菜洗完了以後要切菜 */ public abstract void qiecai(); /** * 然後就是起鍋燒油,寫到這的時候滿腦子德子的聲音 */ public abstract void qiguoshaoyou(); /** * 菜燒好以後需要裝盤就能上桌了 */ public abstract void zhuangpan(); /** * 開始做菜 */ public abstract void cook(); } ``` 然後開始番茄炒蛋: ```java public class TomatoEggs extends AbstractCook { @Override public void xicai() { System.out.println("番茄炒蛋先洗菜"); } @Override public void qiecai() { System.out.println("番茄炒蛋再切菜"); } @Override public void qiguoshaoyou() { System.out.println("現在開始起鍋燒油做番茄炒蛋"); } @Override public void zhuangpan() { System.out.println("番茄炒蛋燒好以後裝盤"); } @Override public void cook() { this.xicai(); this.qiecai(); this.qiguoshaoyou(); this.zhuangpan(); } } ``` 做完了番茄炒蛋,感覺有點不夠吃,再來一個宮保雞丁: ```java public class KungPaoChicken extends AbstractCook { @Override public void xicai() { System.out.println("宮保雞丁先洗菜"); } @Override public void qiecai() { System.out.println("宮保雞丁再切菜"); } @Override public void qiguoshaoyou() { System.out.println("現在開始起鍋燒油做宮保雞丁"); } @Override public void zhuangpan() { System.out.println("宮保雞丁燒好以後裝盤"); } @Override public void cook() { this.xicai(); this.qiecai(); this.qiguoshaoyou(); this.zhuangpan(); } } ``` ![](https://cdn.geekdigging.com/DesignPatterns/03/gongbaojiding.jpg) 程式寫到這裡,好像有哪裡不對,兩個實現類的 `cook()` 方法都是完全相同的,那這個 `cook()` 方法的實現應該出現在抽象類,不應該在實現類上,抽象是所有子類的共性封裝。 程式碼修改一下,把剛才做菜的那個抽象模型修改一下: ```java public abstract class AbstractCook { /** * 做菜第一步就是先洗菜 */ public abstract void xicai(); /** * 菜洗完了以後要切菜 */ public abstract void qiecai(); /** * 然後就是起鍋燒油,寫到這的時候滿腦子德子的聲音 */ public abstract void qiguoshaoyou(); /** * 菜燒好以後需要裝盤就能上桌了 */ public abstract void zhuangpan(); /** * 開始做菜,在抽象類裡直接定義執行過程 */ public void cook(){ this.xicai(); this.qiecai(); this.qiguoshaoyou(); this.zhuangpan(); } } ``` 輸出結果: ```shell 番茄炒蛋先洗菜 番茄炒蛋再切菜 現在開始起鍋燒油做番茄炒蛋 番茄炒蛋燒好以後裝盤 ``` 好了,這就是模版方法模式,是不是感覺很簡單,經常會見到或者經常會用到。對的,沒毛病,你經常在使用,但你不知道這是模板方法模式, ## 3. 定義 模板方法模式(Template Method Pattern): Define the skeleton of an algorithm in an operation,deferring some steps tosubclasses.Template Method lets subclasses redefine certain steps of analgorithm without changing the algorithm's structure.(定義一個操作中的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。) ![](https://cdn.geekdigging.com/DesignPatterns/03/mobanmoshi_UML.png) 在這張類圖裡面, AbstractClass 叫做抽象模板,它的方法分為兩類: - 基本方法:由子類實現,並且在模板方法被呼叫。 - 模板方法:可以有一個或幾個,一般是一個具體方法,也就是一個框架,實現對基本方法的排程,完成固定的邏輯。 > 為了防止惡意的操作,一般模板方法都加上final關鍵字,不允許被覆寫。 下面是模版方法模式的通用程式碼: **抽象模板類:** ```java public abstract class AbstractClass { // 基本方法 protected abstract void doSomething(); // 基本方法 protected abstract void doAnything(); // 模板方法 public final void templateMethod() { this.doSomething(); this.doAnything(); } } ``` **具體模板類:** ```java public class ConcreteClass1 extends AbstractClass { @Override protected void doSomething() { // 邏輯處理 } @Override protected void doAnything() { // 邏輯處理 } } public class ConcreteClass2 extends AbstractClass { @Override protected void doSomething() { // 邏輯處理 } @Override protected void doAnything() { // 邏輯處理 } } ``` **優點:** - 封裝不變部分,擴充套件可變部分。 - 提取公共部分程式碼,便於維護。 - 行為由父類控制,子類