首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-04-24 18:47
  • 3659
  • 13643
juejin.cn

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

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

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

模板方法模式(Template Method Pattern) 定义了一个算法的骨架,将算法中的具体步骤延迟到子类中实现。模板方法模式让子类在不改变算法结构的前提下,重新定义算法中的某些具体步骤,核心解决:

  • 代码复用:将算法的公共步骤封装在父类中,避免子类重复实现。
  • 算法扩展:子类可以通过重写父类的具体步骤来扩展算法的实现。
  • 流程控制:父类控制算法的整体流程,子类负责具体步骤的实现,确保算法的步骤顺序不变。

核心思想与 UML 类图(PlantUML 语法)

模板方法模式包含抽象类(Abstract Class)和具体子类(Concrete Class)。抽象类中定义了模板方法(Template Method)和若干基本方法(Primitive Methods),模板方法定义了算法的骨架,基本方法包括具体方法和抽象方法,具体方法在抽象类中已经实现,抽象方法在子类中实现。

PlantUML Diagram

二、核心实现:电商订单处理流程

1. 定义抽象订单类(模板类)

java
代码解读
复制代码
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. 实现具体订单类(普通订单)

java
代码解读
复制代码
public class NormalOrder extends AbstractOrder { @Override protected void pay() { System.out.println("普通订单使用支付宝支付"); } @Override protected void deliverGoods() { System.out.println("普通订单使用普通快递发货"); } }

3. 实现具体订单类(秒杀订单)

java
代码解读
复制代码
public class FlashSaleOrder extends AbstractOrder { @Override protected void pay() { System.out.println("秒杀订单使用微信支付(优先扣款)"); } @Override protected void deliverGoods() { System.out.println("秒杀订单使用顺丰快递加急发货"); } }

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

java
代码解读
复制代码
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(); } }

输出结果:

plaintext
代码解读
复制代码
处理普通订单: 创建订单 普通订单使用支付宝支付 普通订单使用普通快递发货 通知用户订单处理完成 处理秒杀订单: 创建订单 秒杀订单使用微信支付(优先扣款) 秒杀订单使用顺丰快递加急发货 通知用户订单处理完成

三、进阶:钩子方法(Hook Method)增强模板灵活性

在模板方法模式中,可以通过 钩子方法 来增加算法的灵活性。钩子方法是一个在抽象类中默认实现的方法,子类可以根据需要重写该方法,以控制算法的流程。

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

java
代码解读
复制代码
public abstract class AbstractOrder { // ... 其他方法不变 ... // 钩子方法:是否需要通知用户(默认需要) protected boolean needNotifyUser() { return true; } // 模板方法中调用钩子方法 public final void processOrder() { createOrder(); pay(); deliverGoods(); if (needNotifyUser()) { // 根据钩子方法结果决定是否通知用户 notifyUser(); } } }

2. 子类重写钩子方法(秒杀订单不需要通知用户)

java
代码解读
复制代码
public class FlashSaleOrder extends AbstractOrder { // ... 其他方法不变 ... @Override protected boolean needNotifyUser() { return false; // 秒杀订单不通知用户 } }

3. 客户端测试钩子方法效果

java
代码解读
复制代码
public class ClientDemo { public static void main(String[] args) { // ... 处理普通订单 ... System.out.println("\n处理秒杀订单(不通知用户):"); AbstractOrder flashSaleOrder = new FlashSaleOrder(); flashSaleOrder.processOrder(); } }

输出结果:

plaintext
代码解读
复制代码
处理秒杀订单(不通知用户): 创建订单 秒杀订单使用微信支付(优先扣款) 秒杀订单使用顺丰快递加急发货

四、框架与源码中的模板方法实践

1. Java 的 AbstractList 类

Java 集合框架中的 AbstractList 类是模板方法模式的典型应用。AbstractList 定义了列表的基本操作流程,如 add、get 等方法,具体的实现由子类(如 ArrayList、LinkedList)完成。

java
代码解读
复制代码
public abstract class AbstractList extends AbstractCollection implements List { // 模板方法:获取元素 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)实现。

java
代码解读
复制代码
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { // 模板方法:查询单个对象 public T queryForObject(String sql, RowMapper rowMapper, Object... args) { return execute(sql, new PreparedStatementCallback() { @Override public 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 策略模式

类型核心思想适用场景
模板方法模式定义算法骨架,具体步骤由子类实现算法步骤固定,部分步骤需变化
策略模式定义一系列算法,可动态切换算法实现算法可动态选择,客户端主动切换

理解这种差异,能帮助我们在不同场景下选择更合适的设计模式。

注:本文转载自juejin.cn的AronTing的文章"https://juejin.cn/post/7496340361351446537"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top