👈?上一篇:結構型設計模式對比
文章目錄
- 模板方法模式
- 定義
- 英文原話
- 直譯
- 如何理解呢?
- 2個角色
- 類圖
- 代碼示例
- 應用
- 優點
- 缺點
- 使用場景
- 示例解析:以烹飪過程為例
- 類圖
- 代碼示例
模板方法模式
模板方法模式(Template Method Pattern)是一種行為型設計模式,它通過一個抽象類定義了一個操作的算法骨架,而將一些步驟延遲到子類中實現。
簡而言之,模板方法模式就像是一個烹飪食譜,規定了基本的烹飪流程(算法骨架),但允許廚師根據具體食材(子類)調整某些步驟(如烹飪時間、溫度等),從而制作出不同風味的菜肴。
定義
英文原話
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.
直譯
定義一個操作中的算法框架,進而推遲一些步驟的執行,將其延遲到子類中。模板方法使得子類在不改變算法的結構的情況下,可以改變算法的某些特定步驟。
如何理解呢?
模板方法模式從字面上理解,可以拆分為“模板”和“方法”兩個部分。
- 模板:指的是一種固定的框架或結構,它定義了某個過程或操作的基本流程或步驟。在模板方法模式中,這個“模板”通常由抽象類中的模板方法提供,該方法定義了一個算法的框架,即算法執行的大致步驟和順序。
- 方法:指的是具體的操作或步驟。在模板方法模式中,這些“方法”通常包括抽象方法(由子類實現)和具體方法(在抽象類中實現)。抽象方法定義了算法中需要子類實現的部分,而具體方法則包含了算法中通用的、不需要子類改變的部分。
我們可以以一個簡單的烹飪過程為例。假設我們有一個基本的烹飪流程,其中包含了預熱烤箱、烹飪食物和關閉烤箱的步驟。但不同的食物需要不同的烹飪時間和溫度,這部分就是可以定制的部分。
假設我們想要烤一個蛋糕和一個披薩。兩者都需要預熱烤箱,但烹飪時間和溫度不同,烹飪完成后都需要關閉烤箱。這里,預熱烤箱和關閉烤箱就是模板方法中固定的部分,而烹飪食物則是需要根據不同食物來定制的部分。(見下文示例解析)
2個角色
模板方法模式(Template Method Pattern)中的角色通常包括:
- 抽象類(Abstract Class):這個角色定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作是基本操作,還需要定義一個或幾個模板方法,這些模板方法一般是具體的方法,定義了一個算法的框架。
- 具體子類(Concrete Subclasses):這是抽象模板角色的子類,它們實現抽象模板角色中的抽象方法,以完成算法中與特定子類相關的步驟。
通過使用模板方法模式,開發者可以在不改變算法結構的情況下,通過子類來重定義算法的某些特定步驟,從而實現算法的靈活性和可復用性。
類圖
代碼示例
下面是一個Java示例,展示了模板方法模式:
package com.polaris.designpattern.list3.behavioral.pattern01.templatemethod.classicdemo;// 抽象類,定義了模板方法
abstract class AbstractClass {// 模板方法,定義了算法的框架 public final void templateMethod() {specificMethod1(); // 調用第一個抽象方法 // 可能還有其他的通用操作或條件判斷 specificMethod2(); // 調用第二個抽象方法 }// 抽象操作,子類必須實現 protected abstract void specificMethod1();// 另一個抽象操作,子類也必須實現 protected abstract void specificMethod2();
}// 具體子類A
class ConcreteClassA extends AbstractClass {// 實現抽象操作 @Overrideprotected void specificMethod1() {System.out.println("ConcreteClassA.specificMethod1()");}// 實現抽象操作 @Overrideprotected void specificMethod2() {System.out.println("ConcreteClassA.specificMethod2()");}
}// 具體子類B
class ConcreteClassB extends AbstractClass {// 實現抽象操作 @Overrideprotected void specificMethod1() {System.out.println("ConcreteClassB.specificMethod1()");}// 實現抽象操作 @Overrideprotected void specificMethod2() {System.out.println("ConcreteClassB.specificMethod2()");}
}// 客戶端代碼
public class TemplateMethodTest {public static void main(String[] args) {AbstractClass classA = new ConcreteClassA();classA.templateMethod(); // 輸出 ConcreteClassA.specificMethod1() 和 ConcreteClassA.specificMethod2() AbstractClass classB = new ConcreteClassB();classB.templateMethod(); // 輸出 ConcreteClassB.specificMethod1() 和 ConcreteClassB.specificMethod2() }
}
/* Output:
ConcreteClassA.specificMethod1()
ConcreteClassA.specificMethod2()
ConcreteClassB.specificMethod1()
ConcreteClassB.specificMethod2()
*///~
在這個示例中,
AbstractClass
是抽象類,它定義了一個模板方法templateMethod()
,該方法調用了兩個抽象操作specificMethod1()
和specificMethod2()
。ConcreteClassA
和ConcreteClassB
是具體子類,它們分別實現了這兩個抽象操作。客戶端代碼通過調用模板方法來執行算法,而具體的步驟(specificMethod1()
和specificMethod2()
)則由不同的子類實現。
模板方法模式(Template Method Pattern)是一種行為型設計模式,它定義了一個操作中的算法框架,而將一些步驟延遲到子類中。這使得子類可以不改變一個算法的結構即可重新定義該算法的某些特定步驟。
應用
模板方法模式在以下場景中特別有用:
- 算法復用:當多個類有相似的行為,但部分行為需要定制時,可以使用模板方法模式。
- 框架設計:在框架設計中,模板方法模式可以幫助實現一些可擴展的、可定制的框架。
- 一次性算法:如果一個算法很少改變,但其中的某些步驟可能需要根據具體情況進行定制時,可以使用模板方法模式。
優點
- 代碼復用:模板方法模式通過把不變行為搬到超類,去除了子類中的重復代碼。
- 擴展性好:子類可以通過實現或重寫抽象方法或鉤子方法來改變或擴展算法的部分行為。
- 靈活性高:在模板方法模式中,可以通過定義抽象方法和鉤子方法來實現算法的靈活性和可擴展性。
- 符合開閉原則:對擴展開放,對修改關閉。在模板方法模式中,增加新的功能可以通過增加新的子類來實現,而不需要修改現有的代碼。
缺點
- 抽象層次提高:模板方法模式會增加類的抽象層次,使得子類之間的關系更加復雜。
- 可能產生過多子類:如果每個不同的行為都使用子類來實現,那么類的個數可能會急劇增加。
- 性能考慮:由于使用了繼承,如果子類過多,可能會影響系統的性能。
使用場景
- 創建框架:當我們需要創建一個框架,并希望這個框架具有可擴展性和可定制性時,可以使用模板方法模式。
- 實現回調:在某些情況下,我們可能需要讓子類在特定的事件發生時執行一些操作,這時可以使用模板方法模式來實現回調。
- 資源初始化:當資源的初始化或清理具有固定的流程,但某些步驟可能需要根據具體情況進行定制時,可以使用模板方法模式。
- 算法復用:當多個類有相似的行為,但部分行為需要根據具體情況進行定制時,可以使用模板方法模式來復用代碼。
模板方法模式是一種非常實用的設計模式,它可以幫助我們更好地組織代碼,提高代碼的可維護性和可擴展性。
示例解析:以烹飪過程為例
假設我們有一個基本的烹飪流程,其中包含了預熱烤箱、烹飪食物和關閉烤箱的步驟。但不同的食物需要不同的烹飪時間和溫度,這部分就是可以定制的部分。
假設我們想要烤一個蛋糕和一個披薩。兩者都需要預熱烤箱,但烹飪時間和溫度不同,烹飪完成后都需要關閉烤箱。這里,預熱烤箱和關閉烤箱就是模板方法中固定的部分,而烹飪食物則是需要根據不同食物來定制的部分。
類圖
代碼示例
package com.polaris.designpattern.list3.behavioral.pattern01.templatemethod.cookingdemo;// 抽象類,代表烹飪流程
abstract class CookingProcess {// 模板方法,定義了烹飪的整個過程 public final void cook() {preheatOven(); // 預熱烤箱 cookFood(); // 烹飪食物(需要子類實現) turnOffOven(); // 關閉烤箱 }// 預熱烤箱的具體方法,不需要子類改變 protected void preheatOven() {System.out.println("Preheating oven to 350°F...");// 假設預熱完成需要一些時間,這里省略等待邏輯 }// 烹飪食物的方法,需要子類實現 protected abstract void cookFood();// 關閉烤箱的具體方法,不需要子類改變 protected void turnOffOven() {System.out.println("Turning off the oven...");}
}// 蛋糕烹飪類
class CakeCooking extends CookingProcess {// 實現烹飪食物的方法,這里是烹飪蛋糕 @Overrideprotected void cookFood() {System.out.println("Baking cake for 30 minutes...");// 假設烹飪完成需要一些時間,這里省略等待邏輯 }
}// 披薩烹飪類
class PizzaCooking extends CookingProcess {// 實現烹飪食物的方法,這里是烹飪披薩 @Overrideprotected void cookFood() {System.out.println("Baking pizza for 15 minutes at 450°F...");// 假設烹飪完成需要一些時間,這里省略等待邏輯 }
}// 客戶端代碼
public class CookingDemo {public static void main(String[] args) {CookingProcess cakeCooking = new CakeCooking();cakeCooking.cook(); // 烹飪蛋糕 System.out.println("--------------------");CookingProcess pizzaCooking = new PizzaCooking();pizzaCooking.cook(); // 烹飪披薩 }
}
/* Output:
Preheating oven to 350°F...
Baking cake for 30 minutes...
Turning off the oven...
--------------------
Preheating oven to 350°F...
Baking pizza for 15 minutes at 450°F...
Turning off the oven...
*///~
這個例子展示了模板方法模式如何幫助我們在保持烹飪流程基本框架不變的情況下,為不同的食物定制不同的烹飪步驟。