設計模式(二十三)行為型:模板方法模式詳解

設計模式(二十三)行為型:模板方法模式詳解

模板方法模式(Template Method Pattern)是 GoF 23 種設計模式中的行為型模式之一,其核心價值在于定義一個操作中的算法骨架,而將一些步驟延遲到子類中實現,使得子類可以在不改變算法結構的前提下重新定義算法的某些特定步驟。它通過“父類控制流程,子類實現細節”的方式,實現了代碼復用與行為擴展的完美平衡。模板方法模式是構建框架、標準化流程、實現鉤子機制、統一處理邏輯(如數據處理、構建流程、業務審批流)的基石,是“好萊塢原則”(Don’t call us, we’ll call you)在面向對象設計中的經典體現。

一、詳細介紹

模板方法模式解決的是“多個類實現同一算法,算法結構相同但某些步驟的具體實現不同,且需要防止子類改變整體流程”的問題。在傳統設計中,每個類可能都實現完整的算法,導致大量重復代碼;或者使用條件分支,導致邏輯混亂。模板方法模式通過抽象類定義算法的固定骨架(模板方法),將可變步驟聲明為抽象方法或鉤子方法,由子類實現

該模式包含以下核心角色:

  • AbstractClass(抽象類):定義算法的骨架(模板方法),該方法通常是一個 final 方法,防止子類覆蓋。它包含:
    • 模板方法(Template Method):定義算法的步驟順序,調用原語操作(Primitive Operations)。
    • 抽象原語操作(Abstract Primitive Operations):聲明為 abstract,必須由子類實現,代表算法中可變的步驟。
    • 具體原語操作(Concrete Primitive Operations):在抽象類中提供默認實現,子類可選擇性覆蓋。
    • 鉤子方法(Hook Methods):在抽象類中提供空實現或默認實現的 protected 方法,子類可選擇性覆蓋以“掛鉤”到算法流程中,實現條件邏輯或擴展點。
  • ConcreteClass(具體子類):繼承 AbstractClass,實現所有抽象原語操作,并可選擇性覆蓋具體原語操作或鉤子方法,以定制算法的特定行為。

模板方法模式的關鍵優勢:

  • 代碼復用:算法骨架在父類中定義,避免重復。
  • 控制流程:父類控制算法的整體結構,防止子類破壞流程。
  • 擴展性:子類通過實現抽象方法或覆蓋鉤子來擴展行為。
  • 符合開閉原則:新增行為通過添加新子類實現,無需修改父類。
  • 標準化:強制所有子類遵循相同的算法流程。

與“策略模式”相比,策略模式在運行時通過組合選擇算法,模板方法在編譯時通過繼承固定流程;策略更靈活,模板方法更強調流程控制。與“狀態模式”相比,狀態模式關注狀態驅動的行為切換,模板方法關注流程中步驟的定制。與“命令模式”相比,命令封裝請求,模板方法封裝算法結構

模板方法模式適用于:

  • 框架設計(如 Spring MVC 的 AbstractController)。
  • 標準化業務流程(如訂單處理、審批流)。
  • 構建工具(如編譯、打包、部署流程)。
  • 數據處理管道(如 ETL 流程)。
  • 圖形渲染流程。
  • 單元測試框架的 setUp/tearDown

二、模板方法模式的UML表示

以下是模板方法模式的標準 UML 類圖:

extends
extends
?abstract?
AbstractClass
+templateMethod()
+concreteOperation()
+hookMethod()
+primitiveOperation1()
+primitiveOperation2()
ConcreteClassA
+primitiveOperation1()
+primitiveOperation2()
+hookMethod()
ConcreteClassB
+primitiveOperation1()
+primitiveOperation2()

圖解說明

  • AbstractClass 定義 templateMethod()(通常為 final),它按固定順序調用 primitiveOperation1(), primitiveOperation2(), concreteOperation(), hookMethod()
  • primitiveOperation1()primitiveOperation2() 是抽象方法,必須由子類實現。
  • concreteOperation() 在父類中有具體實現,子類可覆蓋。
  • hookMethod() 是鉤子,有默認實現(可能為空),子類可選擇性覆蓋以插入自定義邏輯。
  • ConcreteClassAConcreteClassB 實現抽象方法,并可選擇覆蓋其他方法。

三、一個簡單的Java程序實例及其UML圖

以下是一個跨平臺軟件構建流程的示例,包含編譯、測試、打包、部署步驟,不同平臺(Windows, Linux)實現不同。

Java 程序實例
// 抽象類:軟件構建流程
abstract class SoftwareBuildProcess {// 模板方法:定義構建流程的骨架 (final 防止子類修改流程)public final void build() {System.out.println("🚀 開始構建流程...");checkoutCode();compile();runTests();// 鉤子方法:子類可決定是否打包if (shouldPackage()) {packageApplication();}// 鉤子方法:子類可決定是否部署if (shouldDeploy()) {deploy();}cleanup();System.out.println("? 構建流程完成。\n");}// 具體原語操作:在抽象類中實現,所有子類共享private void checkoutCode() {System.out.println("  🔁 1. 檢出代碼 (從版本控制系統)");// 模擬操作}// 具體原語操作:提供默認實現,子類可覆蓋protected void cleanup() {System.out.println("  🧹 6. 清理臨時文件 (默認實現)");// 默認清理邏輯}// 鉤子方法:提供默認行為(true/false),子類可覆蓋以控制流程protected boolean shouldPackage() {return true; // 默認打包}protected boolean shouldDeploy() {return false; // 默認不部署}// 抽象原語操作:必須由子類實現protected abstract void compile();protected abstract void runTests();protected abstract void packageApplication();protected abstract void deploy();
}// 具體子類:Windows 構建流程
class WindowsBuildProcess extends SoftwareBuildProcess {@Overrideprotected void compile() {System.out.println("  ??  2. 在 Windows 上編譯 (使用 MSVC)");// 調用 Windows 編譯器}@Overrideprotected void runTests() {System.out.println("  🧪 3. 運行 Windows 測試套件");// 執行 Windows 測試}@Overrideprotected void packageApplication() {System.out.println("  📦 4. 打包為 Windows 安裝程序 (.exe)");// 生成 .exe 安裝包}@Overrideprotected void deploy() {System.out.println("  🚀 5. 部署到 Windows 服務器");// 部署邏輯}// 覆蓋鉤子:Windows 構建默認不部署@Overrideprotected boolean shouldDeploy() {return false;}// 覆蓋具體方法:Windows 特定的清理@Overrideprotected void cleanup() {System.out.println("  🧹 6. 清理 Windows 臨時文件和 .obj 文件");// Windows 清理邏輯}
}// 具體子類:Linux 構建流程
class LinuxBuildProcess extends SoftwareBuildProcess {@Overrideprotected void compile() {System.out.println("  ??  2. 在 Linux 上編譯 (使用 GCC)");// 調用 GCC 編譯器}@Overrideprotected void runTests() {System.out.println("  🧪 3. 運行 Linux 測試套件");// 執行 Linux 測試}@Overrideprotected void packageApplication() {System.out.println("  📦 4. 打包為 Linux 包 (.deb 或 .rpm)");// 生成 .deb 包}@Overrideprotected void deploy() {System.out.println("  🚀 5. 部署到 Linux 服務器 (使用 SSH)");// 部署邏輯}// 覆蓋鉤子:Linux 構建在 CI 環境中自動部署@Overrideprotected boolean shouldDeploy() {// 可根據環境變量決定return System.getenv("CI_ENV") != null;}// 覆蓋鉤子:Linux 構建時,如果測試失敗則不打包@Overrideprotected boolean shouldPackage() {// 簡化:假設測試總是通過return true;}
}// 具體子類:快速構建(跳過測試和打包,僅用于開發)
class QuickBuildProcess extends SoftwareBuildProcess {@Overrideprotected void compile() {System.out.println("  ? 2. 快速編譯 (僅編譯修改的文件)");// 快速編譯邏輯}@Overrideprotected void runTests() {System.out.println("  ??  3. 跳過測試 (開發模式)");// 不運行測試}@Overrideprotected void packageApplication() {System.out.println("  ??  4. 跳過打包 (開發模式)");// 不打包}@Overrideprotected void deploy() {System.out.println("  ??  5. 跳過部署 (開發模式)");// 不部署}// 覆蓋鉤子:快速構建不打包@Overrideprotected boolean shouldPackage() {return false;}// 覆蓋鉤子:快速構建不部署@Overrideprotected boolean shouldDeploy() {return false;}
}// 客戶端使用示例
public class TemplateMethodPatternDemo {public static void main(String[] args) {System.out.println("🏗?  跨平臺軟件構建系統 - 模板方法模式示例\n");// 構建 Windows 版本System.out.println("--- 構建 Windows 版本 ---");SoftwareBuildProcess windowsBuild = new WindowsBuildProcess();windowsBuild.build();// 構建 Linux 版本System.out.println("--- 構建 Linux 版本 ---");SoftwareBuildProcess linuxBuild = new LinuxBuildProcess();// 模擬 CI 環境System.setProperty("CI_ENV", "true");linuxBuild.build();// 開發者快速構建System.out.println("--- 開發者快速構建 ---");SoftwareBuildProcess quickBuild = new QuickBuildProcess();quickBuild.build();}
}
實例對應的UML圖(簡化版)
extends
extends
extends
?abstract?
SoftwareBuildProcess
+build()
-checkoutCode()
+cleanup()
+shouldPackage()
+shouldDeploy()
+compile()
+runTests()
+packageApplication()
+deploy()
WindowsBuildProcess
+compile()
+runTests()
+packageApplication()
+deploy()
+cleanup()
+shouldDeploy()
LinuxBuildProcess
+compile()
+runTests()
+packageApplication()
+deploy()
+shouldPackage()
+shouldDeploy()
QuickBuildProcess
+compile()
+runTests()
+packageApplication()
+deploy()
+shouldPackage()
+shouldDeploy()

運行說明

  • SoftwareBuildProcess 定義 build() 模板方法,固定流程:檢出 -> 編譯 -> 測試 -> (條件打包) -> (條件部署) -> 清理。
  • compile(), runTests(), packageApplication(), deploy() 是抽象方法,由子類實現。
  • cleanup() 是具體方法,有默認實現,子類可覆蓋。
  • shouldPackage()shouldDeploy() 是鉤子方法,子類可覆蓋以控制流程分支。
  • WindowsBuildProcess, LinuxBuildProcess, QuickBuildProcess 實現各自平臺的細節,并通過覆蓋鉤子定制流程。

四、總結

特性說明
核心目的定義算法骨架,延遲步驟實現到子類
實現機制抽象類定義模板方法(final),子類實現抽象方法
優點代碼復用、控制流程、符合開閉原則、標準化流程、支持鉤子擴展
缺點依賴繼承(靈活性低于組合)、類爆炸(過多子類)、父類改動影響所有子類
適用場景框架設計、標準化流程、構建腳本、數據處理管道、業務審批流
不適用場景流程不固定、需要運行時動態組合行為、避免繼承的場景

模板方法模式使用建議

  • 模板方法通常聲明為 final,防止子類破壞流程。
  • 鉤子方法是強大的擴展點,用于條件邏輯或可選步驟。
  • 可結合“工廠方法模式”創建具體子類。
  • 在 Java 中,Comparatorcompare() 可視為一種函數式模板方法。

架構師洞見:
模板方法模式是“框架設計”的靈魂。在現代架構中,其思想已演變為框架與庫的根本區別:庫是“你調用我”,框架是“我調用你”(好萊塢原則)。Spring 框架的 JdbcTemplate, RestTemplate 是其典型應用;JUnit 的 @Before, @After 是鉤子方法;Servlet 的 doGet(), doPost() 是模板方法的變體;構建工具(Maven, Gradle)的生命周期是模板方法的宏觀體現。

未來趨勢是:模板方法將與函數式編程融合,模板方法接受函數式接口作為步驟(如 Java 8 的 Consumer, Function);在低代碼/無代碼平臺中,可視化流程設計器生成模板方法代碼;在AI 工作流中,AI Agent 的“規劃-執行-反思”循環可建模為模板方法;在量子軟件中,量子算法的通用步驟(初始化、操作、測量)可定義為模板。

掌握模板方法模式,是設計可復用框架、標準化系統的核心能力。作為架構師,應在設計任何需要“統一流程、定制細節”的模塊時,優先考慮模板方法模式。它不僅是模式,更是系統秩序的基石——它用不變的骨架約束變化的細節,用父類的權威保障流程的正確,用子類的自由激發實現的創新,從而構建出既穩定又靈活、既統一又多樣的軟件生態系統。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91287.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91287.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91287.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Postgresql 查詢使用正則

今天接到任務,要從數據庫中查詢數據,對于postgresql 我并不熟悉,問了百度,問了通義千問。發現Postgresql 在寫query sql 的時候,可以使用正則匹配,不單是使用like 這種關鍵字。我像發現了新大陸一樣的興奮。…

【WRF-Chem Emissions教程第八期】轉換實用程序

轉換實用程序 8.1 將中間二進制文件轉換為 WRF-Chem 數據文件 文件命名規范與風格 8.2 Binary data file format(中間二進制排放數據文件的格式和結構) FORTRAN 示例程序說明 8.3 Building the WRF-Chemistry emissions conversion code 編譯步驟 驗證編譯結果 8.4 Namelist …

Qt Ribbon效果界面

實現效果&#xff1a;頭文件&#xff1a;#pragma once #include <QMdiArea> #include <QMdiSubWindow> #include <QMainWindow> #include "ui_MainFrame1.h" #include "DockManager.h" #include "DockAreaWidget.h"class Main…

如何修改 MySQL 8.0 的密碼,和忘記密碼時如何修改

要修改 MySQL 8.0 的密碼&#xff0c;可以通過以下幾種方法實現&#xff1a;方法 1&#xff1a;使用 ALTER USER 命令&#xff08;推薦&#xff09;這是 MySQL 8.0 推薦的修改密碼方式&#xff1a;-- 修改當前登錄用戶的密碼 ALTER USER USER() IDENTIFIED BY 新密碼;-- 修改指…

圖像處理控件Aspose.Imaging教程:使用 C# 編程將 CMX 轉換為 PNG

PNG圖像文件格式是廣泛使用的圖像格式之一。這種圖像文件格式提供了增強的共享和顯示功能。另一方面&#xff0c;CMX也是 Corel 應用程序主要使用的圖像文件格式。然而&#xff0c;將 CMX 轉換為 PNG 可以幫助用戶在網絡上查看和共享文件。因此&#xff0c;在本指南中&#xff…

迪麗熱巴寫真壁紙

下載&#xff1a;https://pan.quark.cn/s/a740dbac8274迪麗熱巴絕美寫真&#xff0c;高清壁紙展現獨特魅力&#xff0c;每一張都是視覺盛宴

C++11 std::function 詳解:通用多態函數包裝器

在C11標準中&#xff0c;引入了std::function這一通用多態函數包裝器&#xff0c;定義于<functional>頭文件中。它徹底改變了C中函數對象的使用方式&#xff0c;為不同類型的可調用實體提供了統一的接口。std::function能夠存儲、復制和調用任何可復制構造的可調用目標&a…

Kafka運維實戰 16 - kafka 分區重新分配【實戰】

?? Kafka運維實戰 (17篇) ??Kafka運維實戰 17 - kafka 分區副本從 1 增加到 3【實戰】 ??Kafka運維實戰 16 - kafka 分區重新分配【實戰】 ??Kafka運維實戰 15 - kafka 重設消費者組位移入門和實戰【實戰】 ??Kafka運維實戰 14 - kafka消費者組消費進度(Lag)深入理…

智匯AI,應用領航 | 華宇萬象問數入選2025全景賦能典型案例

7月29日&#xff0c;以“AI城市&#xff1a;數啟新紀元”為主題中關村人工智能與未來城市論壇在中關村國家自主創新示范區展示中心舉辦。本次論壇圍繞人工智能創新應用落地實踐、新型數據基礎設施建設、數據要素價值釋放機制、城市智能治理等關鍵議題&#xff0c;邀請院士專家和…

sqli-labs:Less-7關卡詳細解析

1. 思路&#x1f680; 本關的SQL語句為&#xff1a; $sql"SELECT * FROM users WHERE id(($id)) LIMIT 0,1";注入類型&#xff1a;字符串型&#xff08;單引號、雙括號包裹&#xff09;提示&#xff1a;參數id需以))閉合 同樣無法像常規一樣回顯&#xff0c;php輸出語…

編程算法:從理論基石到產業變革的核心驅動力

文章目錄 算法的本質與效率衡量 基礎算法范式的實踐價值 排序算法的演進與選擇 動態規劃的實用技巧 算法在現代技術棧中的應用 大數據處理的算法框架 編譯器中的算法優化 算法驅動的產業變革 金融領域的算法應用 醫療健康領域的算法創新 制造業的算法優化 算法的未來趨勢 結語 …

深度學習中的注意力機制:原理、應用與未來展望

在人工智能領域&#xff0c;深度學習技術已經取得了巨大的突破&#xff0c;而注意力機制&#xff08;Attention Mechanism&#xff09;作為深度學習中的一個重要概念&#xff0c;正在逐漸改變我們對模型的理解和應用。本文將深入探討注意力機制的原理、在不同領域的應用以及未來…

LeetCode 4:尋找兩個正序數組的中位數

LeetCode 4&#xff1a;尋找兩個正序數組的中位數問題定義與核心挑戰 給定兩個有序&#xff08;升序&#xff09;數組 nums1 和 nums2&#xff0c;要求找到它們的中位數&#xff0c;且算法時間復雜度為 O(log(mn))&#xff08;m 和 n 分別是兩個數組的長度&#xff09;。 中位數…

獨立站如何吃掉平臺蛋糕?DTC模式下的成本重構與利潤躍升

一、成本結構革命&#xff1a;從「流量稅」到「用戶終身價值」亞馬遜賣家需支付15%傭金12%廣告費&#xff0c;導致每$100收入中平臺抽成$27。而成熟獨立站通過SEO&#xff08;自然流量占比超40%&#xff09;和社交媒體內容引流&#xff0c;將獲客成本壓縮至$8-$15。更關鍵的是用…

應用驅動 協同創新:中國人工智能開啟高質量發展新篇章

人工智能技術的突破性發展正引發全球產業格局的深刻變革。在2025年這個關鍵節點&#xff0c;中國以"應用導向"為戰略支點&#xff0c;依托新型舉國體制優勢&#xff0c;正在構建具有中國特色的人工智能發展體系&#xff0c;為全球智能革命貢獻東方智慧。一、戰略布局…

ZKMall商城開源本地部署指南

1. 開發環境配置 以下是開發工具的最低版本要求。在繼續之前&#xff0c;請務必安裝所有必需的依賴項。 工具版本JDK17MySQL5.7.3Redis5.0Maven3.9.5NodeJS20.18.0 1.1 安裝資源 如需詳細的安裝指南&#xff0c;您可以參考以下教程&#xff1a; JDK: 菜鳥教程 Java 環境搭建…

《使用Qt Quick從零構建AI螺絲瑕疵檢測系統》——8. AI賦能(下):在Qt中部署YOLOv8模型

目錄一、概述1.1 背景介紹&#xff1a;從“訓練”到“部署”1.2 學習目標二、在C中集成ONNX模型2.1 準備模型文件2.2 修改Backend以加載和運行模型三、關鍵一步&#xff1a;輸出結果的后處理四、運行與驗證五、總結與展望一、概述 1.1 背景介紹&#xff1a;從“訓練”到“部署…

【動態規劃 | 多狀態問題】動態規劃求解多狀態問題

算法相關知識點可以通過點擊以下鏈接進行學習一起加油&#xff01;斐波那契數列模型路徑問題多狀態問題通常涉及多個決策點和狀態轉換&#xff0c;解決起來復雜且計算量大。動態規劃作為一種強大的算法工具&#xff0c;能夠通過將問題分解為子問題并逐步求解&#xff0c;顯著提…

【HTTP】防XSS+SQL注入:自定義HttpMessageConverter過濾鏈深度解決方案

防XSSSQL注入&#xff1a;自定義HttpMessageConverter過濾鏈深度解決方案一、安全威脅模型分析二、自定義HttpMessageConverter架構設計2.1 技術棧組成三、完整實現代碼3.1 安全過濾工具類3.2 自定義HttpMessageConverter3.3 Spring安全配置四、深度防御增強方案4.1 SQL注入參數…

學習游戲制作記錄(凍結敵人時間與黑洞技能)7.30

1.實現劍擊中敵人時凍結敵人時間Enemy腳本&#xff1a;public float defaultMoveSpeed;//默認速度defaultMoveSpeed moveSpeed;//Awake&#xff08;&#xff09;中設置public virtual void FreezeTime(bool _timeFreeze)//凍結設置函數{if (_timeFreeze){moveSpeed 0;anim.sp…