模板方法模式:定义算法骨架的设计模式

模板方法模式:定义算法骨架的设计模式

一、模式核心:模板方法定义算法骨架,具体步骤延迟到子类实现

在软件开发中,经常会遇到这样的情况:某个算法的步骤是固定的,但具体步骤的实现可能因不同情况而有所不同。例如,在电商系统中,订单的处理流程通常包括创建订单、支付、发货、通知用户等步骤,但不同类型的订单(如普通订单、秒杀订单)在支付和发货环节的实现可能不同。

模板方法模式(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.mzph.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;系统视角/抽象建模&…