模板方法模式
模板方法模式是一種行為型設計模式,它定義了一個算法的骨架,將一些步驟延遲到子類中實現。這種模式允許子類在不改變算法結構的情況下重新定義算法的某些步驟。
結構
-
抽象類(Abstract Class):負責給出一個算法的輪廓和骨架。它由一個模板方法和若干個基本方法構成。其中包含了一些基本操作的步驟,有些步驟由具體子類實現。
-
模板方法:定義了算法的骨架,按某種順序調用其包含的基本方法。
-
基本方法:是實現算法各個步驟的方法,是模板方法的組成部分。基本方法又可以分為三種:
-
抽象方法(Abstract Method) :一個抽象方法由抽象類聲明、由其具體子類實現。
-
具體方法(Concrete Method) :一個具體方法由一個抽象類或具體類聲明并實現,其子類可以進行覆蓋也可以直接繼承。
-
鉤子方法(Hook Method) :在抽象類中已經實現,包括用于判斷的邏輯方法和需要子類重寫的空方法兩種。
一般鉤子方法是用于判斷的邏輯方法,這類方法名一般為isXxx,返回值類型為boolean類型。
-
-
-
具體子類(Concrete Class):實現抽象類中所定義的抽象方法和鉤子方法,它們是一個頂級邏輯的組成步驟。
案例:
你制作一個飲料,步驟是確定的,像燒水; 釀造;倒入杯中,添加調味品。燒水和倒杯是固定的基本操作,釀造和添加調味料這個則是通過具體的情況來定的。
代碼實現:
// 抽象類
abstract class Beverage {// 模板方法,定義了算法的骨架public final void prepareBeverage() {boilWater();brew();pourInCup();addCondiments();}// 抽象方法,由子類實現abstract void brew();abstract void addCondiments();// 公共方法,由父類實現void boilWater() {System.out.println("Boiling water");}void pourInCup() {System.out.println("Pouring into cup");}
}// 具體類1
class Coffee extends Beverage {@Overridevoid brew() {System.out.println("Dripping coffee through filter");}@Overridevoid addCondiments() {System.out.println("Adding sugar and milk");}
}// 具體類2
class Tea extends Beverage {@Overridevoid brew() {System.out.println("Steeping the tea");}@Overridevoid addCondiments() {System.out.println("Adding lemon");}
}// 使用示例
public class Main {public static void main(String[] args) {Beverage coffee = new Coffee();coffee.prepareBeverage();System.out.println();Beverage tea = new Tea();tea.prepareBeverage();}
}
注意:為防止惡意操作,一般模板方法都加上 final 關鍵詞。
使用場景:
- 當有一系列算法步驟,其中有一部分是固定的,但是另一部分需要在子類中具體實現時,可以考慮使用模板方法模式。
- 當需要在不同的子類中重用相同的算法框架時,可以使用模板方法模式。
以下是模板方法模式在開發后臺管理系統中的使用場景示例:
- 權限管理: 在后臺管理系統中,通常需要對不同用戶或用戶組的權限進行管理。模板方法模式可以定義一個權限管理的骨架,包括權限驗證、權限分配等操作,而具體的權限驗證和分配操作可以交由子類實現。
- 數據的增刪改查: 后臺管理系統通常需要對數據進行增加、刪除、修改、查詢等操作。可以使用模板方法模式定義一個數據操作的骨架,包括數據的驗證、數據的持久化等步驟,而具體的數據操作可以由子類實現。
- 數據的導入導出: 后臺管理系統可能需要支持數據的導入導出功能,例如從 Excel 文件中導入數據到數據庫,或者將數據庫中的數據導出為 Excel 文件。可以使用模板方法模式定義一個數據導入導出的骨架,包括數據格式的驗證、數據的轉換等步驟,而具體的導入導出操作可以由子類實現。
- 日志記錄: 后臺管理系統通常需要記錄用戶的操作日志,例如登錄日志、操作日志等。可以使用模板方法模式定義一個日志記錄的骨架,包括日志的格式化、日志的存儲等步驟,而具體的日志記錄操作可以由子類實現。
優缺點:
優點:
-
提高代碼復用性
將相同部分的代碼放在抽象的父類中,而將不同的代碼放入不同的子類中。
-
實現了反向控制
通過一個父類調用其子類的操作,通過對子類的具體實現擴展不同的行為,實現了反向控制 ,并符合“開閉原則”。
缺點:
- 對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象。
- 父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了代碼閱讀的難度。