定義:
????????Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.(定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改 變一個算法的結構即可重定義該算法的某些特定步驟。)
模板方法模式通用類圖
????????模板方法設計模式的核心思想是“定義算法骨架,將可變部分延遲到子類實現”。它將算法中不變的部分封裝在抽象類的模板方法中,而將可變的部分抽象成抽象方法或鉤子方法,由子類具體實現。這樣可以避免代碼重復,同時允許子類在不改變算法整體結構的情況下,對某些步驟進行定制化實現。
角色:
模板方法模式包含以下幾個核心角色:
1、抽象類(Abstract Class)
????????抽象類定義了一個模板方法,該方法包含了算法的骨架,具體步驟由一系列方法調用組成。這些方法可以是抽象方法、具體方法或鉤子方法:
- 抽象方法:由抽象類聲明,具體實現由子類完成。
- 具體方法:在抽象類中已經實現,子類可以直接使用或重寫。
- 鉤子方法:在抽象類中提供默認實現,子類可以選擇重寫或不重寫。鉤子方法通常用于控制算法的流程。
2、具體子類(Concrete Class)
????????具體子類繼承自抽象類,實現抽象類中的抽象方法,必要時重寫鉤子方法,以實現特定的業務邏輯。具體子類不改變算法的結構,只負責實現算法中的某些步驟。
代碼示例:
????????咖啡和茶的制作過程有相似的步驟:燒水、沖泡、倒入杯中、添加調料。使用模板方法設計模式實現這兩種飲品的制作過程。
// 抽象類:飲品制作
public abstract class Beverage {// 模板方法:定義制作飲品的算法骨架public final void prepareRecipe() {boilWater();brew();pourInCup();if (customerWantsCondiments()) {addCondiments();}}// 具體方法:燒水protected final void boilWater() {System.out.println("燒開水");}// 抽象方法:沖泡protected abstract void brew();// 具體方法:倒入杯中protected final void pourInCup() {System.out.println("倒入杯中");}// 抽象方法:添加調料protected abstract void addCondiments();// 鉤子方法:是否添加調料,默認添加protected boolean customerWantsCondiments() {return true;}}
// 具體子類:咖啡
public class Coffee extends Beverage {@Overrideprotected void brew() {System.out.println("沖泡咖啡粉");}@Overrideprotected void addCondiments() {System.out.println("添加糖和牛奶");}}
// 具體子類:茶
public class Tea extends Beverage {@Overrideprotected void brew() {System.out.println("浸泡茶葉");}@Overrideprotected void addCondiments() {System.out.println("添加檸檬");}// 重寫鉤子方法,自定義是否添加調料@Overrideprotected boolean customerWantsCondiments() {// 模擬用戶選擇return Math.random() > 0.5;}}
// 客戶端代碼
public class BeverageClient {public static void main(String[] args) {System.out.println("制作咖啡...");Beverage coffee = new Coffee();coffee.prepareRecipe();System.out.println("\n制作茶...");Beverage tea = new Tea();tea.prepareRecipe();}}
優點?:
1.提高代碼復用性:將通用的算法結構放在抽象類中,避免了在多個子類中重復實現相同的代碼,提高了代碼的復用性。
2.簡化子類實現:子類只需實現抽象類中定義的抽象方法和需要重寫的鉤子方法,而不需要關心算法的整體結構,簡化了子類的實現。
3.便于控制算法流程:模板方法模式將算法的控制權集中在抽象類中,子類只能在允許的范圍內進行擴展,便于控制算法的流程和行為。
4.符合開閉原則:當需要修改或擴展算法的某些步驟時,只需創建新的子類,而不需要修改抽象類的代碼,符合開閉原則。
缺點:
1.限制子類靈活性:模板方法模式通過繼承實現代碼復用,子類必須遵循抽象類定義的算法結構,可能會限制子類的靈活性。
2.增加類的數量:隨著算法步驟的增加,抽象類和子類的數量可能會增多,導致系統的類層次結構變得復雜,增加了代碼的理解和維護難度。
3.父類與子類耦合度較高:模板方法模式中,抽象類定義了算法的骨架,子類依賴于抽象類的實現。如果抽象類發生變化,可能會影響到所有的子類,導致父類與子類之間的耦合度較高。
使用場景:
(一)多個算法有相似結構的場景
????????當多個算法或操作具有相似的結構,但某些步驟的實現方式不同時,可以使用模板方法設計模式。將通用的算法結構放在抽象類中,而將不同的步驟實現延遲到子類中,避免代碼重復。
(二)需要控制子類擴展的場景
????????模板方法模式允許在不改變算法整體結構的情況下,通過子類來擴展或修改算法的某些步驟。抽象類可以定義哪些步驟是必須實現的(抽象方法),哪些步驟是可以選擇性實現的(鉤子方法),從而控制子類的擴展方式。
(三)希望提高代碼復用性的場景
????????模板方法設計模式通過繼承實現代碼復用,將通用的代碼放在抽象類中,而將特殊的代碼放在子類中。這樣可以減少代碼冗余,提高代碼的復用性和可維護性。
(四)框架設計場景
????????在框架設計中,模板方法模式經常被用來定義框架的核心流程,而將一些具體的實現細節留給開發者。例如,Java 的 Servlet API 中,HttpServlet 類就使用了模板方法模式,定義了處理 HTTP 請求的基本流程,開發者只需重寫 doGet()、doPost() 等方法即可。?
????????模板方法設計模式通過定義算法的骨架,將可變部分延遲到子類實現,為軟件開發提供了一種優雅的代碼復用和擴展方式。它在多個領域都有廣泛的應用,如游戲開發中的角色行為模式、軟件開發中的框架設計等。合理運用模板方法設計模式,可以使代碼更加簡潔、靈活和易于維護。然而,在使用時也需要注意其缺點,避免過度使用導致類層次結構復雜。通過權衡利弊,我們可以在適當的場景下使用模板方法模式,發揮其最大的優勢。