模板方法模式:定義算法骨架的設計模式

模板方法模式:定義算法骨架的設計模式

一、模式核心:模板方法定義算法骨架,具體步驟延遲到子類實現

在軟件開發中,經常會遇到這樣的情況:某個算法的步驟是固定的,但具體步驟的實現可能因不同情況而有所不同。例如,在電商系統中,訂單的處理流程通常包括創建訂單、支付、發貨、通知用戶等步驟,但不同類型的訂單(如普通訂單、秒殺訂單)在支付和發貨環節的實現可能不同。

模板方法模式(Template Method Pattern) 定義了一個算法的骨架,將算法中的具體步驟延遲到子類中實現。模板方法模式讓子類在不改變算法結構的前提下,重新定義算法中的某些具體步驟,核心解決:

  • 代碼復用:將算法的公共步驟封裝在父類中,避免子類重復實現。
  • 算法擴展:子類可以通過重寫父類的具體步驟來擴展算法的實現。
  • 流程控制:父類控制算法的整體流程,子類負責具體步驟的實現,確保算法的步驟順序不變。

核心思想與 UML 類圖(PlantUML 語法)

模板方法模式包含抽象類(Abstract Class)和具體子類(Concrete Class)。抽象類中定義了模板方法(Template Method)和若干基本方法(Primitive Methods),模板方法定義了算法的骨架,基本方法包括具體方法和抽象方法,具體方法在抽象類中已經實現,抽象方法在子類中實現。

PlantUML Diagram

二、核心實現:電商訂單處理流程

1. 定義抽象訂單類(模板類)

public abstract class AbstractOrder {// 模板方法:訂單處理流程public final void processOrder() {createOrder(); // 創建訂單(具體方法,在抽象類中實現)pay(); // 支付(抽象方法,由子類實現)deliverGoods(); // 發貨(抽象方法,由子類實現)notifyUser(); // 通知用戶(具體方法,在抽象類中實現)}// 具體方法:創建訂單(公共步驟,無需子類重寫)protected void createOrder() {System.out.println("創建訂單");}// 抽象方法:支付(不同訂單類型實現不同)protected abstract void pay();// 抽象方法:發貨(不同訂單類型實現不同)protected abstract void deliverGoods();// 具體方法:通知用戶(公共步驟,無需子類重寫)protected void notifyUser() {System.out.println("通知用戶訂單處理完成");}
}

2. 實現具體訂單類(普通訂單)

public class NormalOrder extends AbstractOrder {@Overrideprotected void pay() {System.out.println("普通訂單使用支付寶支付");}@Overrideprotected void deliverGoods() {System.out.println("普通訂單使用普通快遞發貨");}
}

3. 實現具體訂單類(秒殺訂單)

public class FlashSaleOrder extends AbstractOrder {@Overrideprotected void pay() {System.out.println("秒殺訂單使用微信支付(優先扣款)");}@Overrideprotected void deliverGoods() {System.out.println("秒殺訂單使用順豐快遞加急發貨");}
}

4. 客戶端使用模板方法模式

public class ClientDemo {public static void main(String[] args) {// 處理普通訂單AbstractOrder normalOrder = new NormalOrder();System.out.println("處理普通訂單:");normalOrder.processOrder();System.out.println("\n處理秒殺訂單:");AbstractOrder flashSaleOrder = new FlashSaleOrder();flashSaleOrder.processOrder();}
}

輸出結果

處理普通訂單:
創建訂單
普通訂單使用支付寶支付
普通訂單使用普通快遞發貨
通知用戶訂單處理完成處理秒殺訂單:
創建訂單
秒殺訂單使用微信支付(優先扣款)
秒殺訂單使用順豐快遞加急發貨
通知用戶訂單處理完成

三、進階:鉤子方法(Hook Method)增強模板靈活性

在模板方法模式中,可以通過 鉤子方法 來增加算法的靈活性。鉤子方法是一個在抽象類中默認實現的方法,子類可以根據需要重寫該方法,以控制算法的流程。

1. 添加鉤子方法(是否需要短信通知)

public abstract class AbstractOrder {// ... 其他方法不變 ...// 鉤子方法:是否需要通知用戶(默認需要)protected boolean needNotifyUser() {return true;}// 模板方法中調用鉤子方法public final void processOrder() {createOrder();pay();deliverGoods();if (needNotifyUser()) { // 根據鉤子方法結果決定是否通知用戶notifyUser();}}
}

2. 子類重寫鉤子方法(秒殺訂單不需要通知用戶)

public class FlashSaleOrder extends AbstractOrder {// ... 其他方法不變 ...@Overrideprotected boolean needNotifyUser() {return false; // 秒殺訂單不通知用戶}
}

3. 客戶端測試鉤子方法效果

public class ClientDemo {public static void main(String[] args) {// ... 處理普通訂單 ...System.out.println("\n處理秒殺訂單(不通知用戶):");AbstractOrder flashSaleOrder = new FlashSaleOrder();flashSaleOrder.processOrder();}
}

輸出結果

處理秒殺訂單(不通知用戶):
創建訂單
秒殺訂單使用微信支付(優先扣款)
秒殺訂單使用順豐快遞加急發貨

四、框架與源碼中的模板方法實踐

1. Java 的 AbstractList 類

Java 集合框架中的 AbstractList 類是模板方法模式的典型應用。AbstractList 定義了列表的基本操作流程,如 addget 等方法,具體的實現由子類(如 ArrayListLinkedList)完成。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {// 模板方法:獲取元素public E get(int index) {throw new AbstractMethodError(); // 抽象方法,由子類實現}// 具體方法:添加元素(基于 get 和 set 實現)public boolean add(E e) {add(size(), e); // 調用子類實現的 add(int, E) 方法return true;}
}

2. Spring 的 JdbcTemplate

Spring 框架中的 JdbcTemplate 使用模板方法模式封裝了 JDBC 的操作流程。JdbcTemplate 定義了執行 SQL 的模板方法(如 queryForObject),具體的結果映射由回調接口(如 RowMapper)實現。

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {// 模板方法:查詢單個對象public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) {return execute(sql, new PreparedStatementCallback<T>() {@Overridepublic T doInPreparedStatement(PreparedStatement ps) throws SQLException {ps.execute();ResultSet rs = ps.getResultSet();return rowMapper.mapRow(rs, 1); // 回調接口實現結果映射}}, args);}
}

五、避坑指南:正確使用模板方法模式的 3 個要點

1. 合理設計模板方法的訪問權限

模板方法通常定義為 final 方法,防止子類重寫,確保算法骨架的穩定性。如果需要子類重寫模板方法,可以將其定義為 protected 方法,但需謹慎使用,避免破壞算法結構。

2. 控制抽象類中的抽象方法數量

抽象類中的抽象方法應盡可能少,只包含那些必須由子類實現的步驟。如果抽象方法過多,會導致子類的實現復雜度增加,違背模板方法模式的初衷。

3. 避免在模板方法中調用子類的方法

在模板方法中應優先調用抽象類中的方法,避免直接調用子類的方法,否則可能導致循環依賴或子類未初始化的問題。如果需要調用子類的方法,可以通過抽象方法或鉤子方法實現。

六、總結:何時該用模板方法模式?

適用場景核心特征典型案例
算法步驟固定算法的步驟順序是固定的,但具體步驟實現可變訂單處理流程、考試流程
代碼復用多個子類有共同的算法骨架和部分公共代碼日志記錄器、文件處理器
流程控制需要確保算法步驟的執行順序不被篡改工作流引擎、游戲關卡流程

模板方法模式通過將算法骨架與具體實現分離,實現了代碼的復用和算法的擴展,是一種非常實用的設計模式。下一篇我們將深入探討迭代器模式,解析如何統一遍歷不同數據結構的方式,敬請期待!

擴展思考:模板方法模式 vs 策略模式

類型核心思想適用場景
模板方法模式定義算法骨架,具體步驟由子類實現算法步驟固定,部分步驟需變化
策略模式定義一系列算法,可動態切換算法實現算法可動態選擇,客戶端主動切換

理解這種差異,能幫助我們在不同場景下選擇更合適的設計模式。

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

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

相關文章

淺談Java 內存管理:棧與堆,垃圾回收

在Java編程世界里&#xff0c;內存管理是一項極為關鍵的技能&#xff0c;它就像程序運行背后的“隱形守護者”&#xff0c;默默影響著程序的性能與穩定性。今天&#xff0c;咱們就來簡單學習一下Java內存管理中的兩大核心要點&#xff1a;棧與堆的內存分配機制&#xff0c;以及…

【WebGL小知識】WebGL平臺上不同Json的比較

今天來總結一下WebGL平臺上不同Json插件的差別&#xff0c;話不多說直接開始。 JsonUtility JsonUtility是Unity自帶的Json解析&#xff0c;無需另外安裝插件。 優點&#xff1a; Unity自帶&#xff0c;兼容性好&#xff0c;WebGL平臺可以使用輕量級&#xff0c;性能較好。 …

4.22tx視頻后臺開發一面

總時長大概在一個小時&#xff0c;主要提問C、操作系統、計網以及數據庫等方面&#xff0c;最后兩個算法編程題。 一上來先介紹項目 Linux下的mybash命令處理器和內存池 mybash可以再總結歸納一下&#xff0c;一上來有點緊張沒有條理 內存池是用邊界標識法寫的&#xff0c;…

從StandardMaterial和PBRMaterial到PBRMetallicRoughnessMaterial:Babylon.js材質轉換完全指南

在現代3D圖形開發中&#xff0c;基于物理的渲染(PBR)已成為行業標準。本文將深入探討如何在Babylon.js中將傳統StandardMaterial和PBRMaterial轉換為PBRMetallicRoughnessMaterial&#xff0c;并保持視覺一致性。 為什么需要轉換&#xff1f; PBRMetallicRoughnessMaterial作…

UEditor文檔在Servlet項目上的應用

UEditor 是一款功能強大的富文本編輯器&#xff0c;在項目中應用廣泛。 Ueditor使用 引入 UEditor 下載 UEditor&#xff1a;從 UEditor 官方網站&#xff08;ueditor 官網&#xff09;下載適合項目需求的版本。解壓文件&#xff1a;將下載的壓縮包解壓到項目的靜態資源目錄…

ThinkPHP快速使用手冊

目錄 介紹 安裝&#xff08;windows環境&#xff09; 安裝Composer 安裝ThinkPHP 目錄結構 配置文件 第一個接口&#xff08;Controller層&#xff09; Hello World 自定義Controller 請求參數 獲取查詢參數&#xff08;Get請求&#xff09; 獲取指定請求參數 獲取…

面向 C# 初學者的完整教程

&#x1f9f1; 一、項目結構說明 你的項目大致結構如下&#xff1a; TaskManager/ ├── backend/ │ ├── TaskManager.Core/ // 實體類和接口 │ ├── TaskManager.Infrastructure/ // 數據庫、服務實現 │ └── TaskManager.API/ // We…

Axios 的 GET 和 POST 請求:前端開發中的 HTTP 通信

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

【前端】如何檢查內存泄漏

在實際的場景中&#xff0c;如果觀察到內存持續出現峰值&#xff0c;并且內存消耗一直沒有減少&#xff0c;那可能存在內存泄漏。 使用 Chrome DevTools 來識別內存圖和一些內存泄漏&#xff0c;我們需要關注以下兩個方面&#xff1a; ● 使用性能分析器可視化內存消耗&#xf…

JavaScript的JSON處理Map的弊端

直接使用 Map 會遇到的問題及解決方案 直接使用 Map 會導致數據丟失&#xff0c;因為 JSON.stringify 無法序列化 Map。以下是詳細分析及解決方法&#xff1a; 問題復現 // 示例代碼 const myMap new Map(); myMap.set(user1, { name: Alice }); myMap.set(user2, { name: B…

【數據結構】第五彈——Stack 和 Queue

文章目錄 一. 棧(Stack)1.1 概念1.2 棧的使用1.3 棧的模擬實現1.3.1 順序表結構1.3.2 進棧 壓棧1.3.3 刪除棧頂元素1.3.4 獲取棧頂元素1.3.5 自定義異常 1.4 棧的應用場景1.改變元素序列2. 將遞歸轉化為循環3. 四道習題 1.5 概念分區 二. 隊列(Queue)2.1 概念2.2 隊列的使用2.3…

第七屆能源系統與電氣電力國際學術會議(ICESEP 2025)

重要信息 時間&#xff1a;2025年6月20-22日 地點&#xff1a;中國-武漢 官網&#xff1a;www.icesep.net 主題 能源系統 節能技術、能源存儲技術、可再生能源、熱能與動力工程 、能源工程、可再生能源技術和系統、風力發…

深入解析C++ STL Stack:后進先出的數據結構

一、引言 在計算機科學中&#xff0c;棧&#xff08;Stack&#xff09;作為一種遵循后進先出&#xff08;LIFO&#xff09;?原則的數據結構&#xff0c;是算法設計和程序開發的基礎構件。C STL中的stack容器適配器以簡潔的接口封裝了底層容器的操作&#xff0c;為開發者提供了…

Golang | 自行實現并發安全的Map

核心思路&#xff0c;讀寫map之前加鎖&#xff01;哈希思路&#xff0c;大map化分為很多個小map

Mac 「brew」快速安裝MySQL

安裝MySQL 在 macOS 上安裝 MySQL 環境可以通過Homebrew快速實現&#xff0c;以下是步驟指南&#xff1a; 方法 1&#xff1a;使用 Homebrew 安裝 MySQL 1. 安裝 Homebrew 如果尚未安裝 Homebrew&#xff0c;可以通過以下命令安裝&#xff1a; /bin/bash -c "$(curl -…

【數字孿生世界的搭建之旅:從0到1理解飛渡平臺】

數字孿生世界的搭建之旅&#xff1a;從0到1理解飛渡平臺 前言&#xff1a;數字分身的魔法 想象一下&#xff0c;如果你能在現實世界之外&#xff0c;創造一個物理世界的"分身"&#xff0c;這個分身能完美復制現實中的一切變化&#xff0c;甚至可以預測未來可能發生…

【漏洞復現】Struts2系列

【漏洞復現】Struts2系列 1. 了解Struts21. Struts2 S2-061 RCE &#xff08;CVE-2020-17530&#xff09;1. 漏洞描述2. 影響版本3. 復現過程 1. 了解Struts2 Apache Struts2是一個基于MVC設計模式的Web應用框架&#xff0c;會對某些標簽屬性&#xff08;比如 id&#xff09;的…

[FPGA Video IP] Video Processing Subsystem

Xilinx Video Processing Subsystem IP (PG231) 詳細介紹 概述 Xilinx LogiCORE? IP Video Processing Subsystem (VPSS)&#xff08;PG231&#xff09;是一個高度可配置的視頻處理模塊&#xff0c;設計用于在單一 IP 核中集成多種視頻處理功能&#xff0c;包括縮放&#xf…

自動駕駛(ADAS)功能--相關名稱及縮寫

根據《道路車輛先進駕駛輔助系統&#xff08;ADAS&#xff09;術語及定義》GB/T 39263—2020&#xff0c;如下表格&#xff1a; 編號中文術語英文縮寫定義類別2.1.1先進駕駛輔助系統ADAS利用傳感、通信、決策及執行等裝置&#xff0c;實時監測駕駛員、車輛及行駛環境&#xff…

1.9軟考系統架構設計師:優秀架構設計師 - 超簡記憶要點、知識體系全解、考點深度解析、真題訓練附答案及解析

超簡記憶要點 1. 優秀架構師標準 ? 技術&#xff08;深度/廣度&#xff09; 實戰&#xff08;大型項目&#xff09; 素養&#xff08;溝通/業務前瞻&#xff09; 2. 演化路徑 &#x1f4c8; 積累&#xff08;技術/項目&#xff09; → 思維&#xff08;系統視角/抽象建模&…