文章目录
- 前言
- 一、概念
- 二、核心结构
- 三、Java 代码实现(订单支付流程)
-
- 1. 抽象类(定义模板)
- 2. 具体子类:微信支付
- 3. 具体子类:支付宝支付
- 4. 客户端调用
- 四、钩子方法(Hook)—— 让模板更灵活
- 五、优缺点
-
- 优点
- 缺点
- 六、应用场景
- 七、模板方法 VS 策略模式
- 八、总结
前言
在开发中,我们经常会遇到业务流程固定、但个别步骤实现不同的场景:比如用户注册流程(校验、创建、通知、日志)、支付流程(验签、扣款、回调、日志)、数据导入(解析、校验、保存、通知)。整个流程骨架一样,但某几步具体实现不同。如果每个业务都写一套重复代码,会造成大量冗余、难以维护。模板方法模式就是专门处理这种固定流程+可变步骤的设计模式。
一、概念
模板方法模式(Template Method Pattern) 是一种行为型设计模式, 核心思想: 定义一个算法的骨架流程,将某些步骤的具体实现延迟到子类中,使得子类可以不改变整体流程结构,即可重定义个别步骤。
简单理解:
- 父类(模板):定义整个流程的固定步骤与顺序,不允许子类改变骨架。
- 子类(实现):只重写个别可变步骤,流程不变。
一句话总结: 父类定骨架,子类填细节。
二、核心结构
AbstractClass(抽象类)
- 定义模板方法(final,防止子类重写)
- 定义抽象方法(子类必须实现)
- 定义钩子方法(可选重写)
- 定义通用方法(公共逻辑)
ConcreteClass(具体子类) 实现抽象方法,完成自身业务逻辑。
Client(客户端) 直接调用模板方法。
三、Java 代码实现(订单支付流程)
场景: 所有支付流程都固定为 4 步:
只有第2步不同,完美适合模板方法。
1. 抽象类(定义模板)
public abstract class AbstractPayTemplate {
/**
* 模板方法:固定支付流程
* final 防止子类篡改流程
*/
public final void pay(String orderId) {
checkParam(orderId); // 1.固定
doPay(orderId); // 2.可变
notify(orderId); // 3.固定
log(orderId); // 4.固定
}
// 固定:参数校验
private void checkParam(String orderId) {
System.out.println(orderId + " 参数校验通过");
}
// 抽象:子类必须实现支付逻辑
protected abstract void doPay(String orderId);
// 固定:回调通知
private void notify(String orderId) {
System.out.println(orderId + " 支付成功,回调通知");
}
// 固定:日志
private void log(String orderId) {
System.out.println(orderId + " 支付日志已记录");
}
}
2. 具体子类:微信支付
public class WechatPay extends AbstractPayTemplate {
@Override
protected void doPay(String orderId) {
System.out.println(orderId + " 【微信支付】执行扣款");
}
}
3. 具体子类:支付宝支付
public class AliPay extends AbstractPayTemplate {
@Override
protected void doPay(String orderId) {
System.out.println(orderId + " 【支付宝支付】执行扣款");
}
}
4. 客户端调用
public class Client {
public static void main(String[] args) {
AbstractPayTemplate wechat = new WechatPay();
wechat.pay("ORDER_001");
System.out.println("====================");
AbstractPayTemplate ali = new AliPay();
ali.pay("ORDER_002");
}
}
输出:
ORDER_001 参数校验通过
ORDER_001 【微信支付】执行扣款
ORDER_001 支付成功,回调通知
ORDER_001 支付日志已记录
====================
ORDER_002 参数校验通过
ORDER_002 【支付宝支付】执行扣款
ORDER_002 支付成功,回调通知
ORDER_002 支付日志已记录
四、钩子方法(Hook)—— 让模板更灵活
钩子方法是默认空实现/返回true的方法,子类可以选择性重写,控制流程是否执行某一步。
示例:增加是否需要回调的钩子:
public abstract class AbstractPayTemplate {
public final void pay(String orderId) {
checkParam(orderId);
doPay(orderId);
// 钩子控制是否执行通知
if (needNotify()) {
notify(orderId);
}
log(orderId);
}
// 钩子方法:默认需要通知
protected boolean needNotify() {
return true;
}
// … 其他不变
}
子类可以重写钩子:
public class WechatPayNoNotify extends AbstractPayTemplate {
@Override
protected void doPay(String orderId) {
System.out.println(orderId + " 微信支付(无通知)");
}
// 重写钩子:关闭通知
@Override
protected boolean needNotify() {
return false;
}
}
五、优缺点
优点
缺点
六、应用场景
凡是流程固定、个别步骤不同的场景:
经典源码应用:
- Java Servlet doGet/doPost
- Spring JdbcTemplate、RestTemplate
- MyBatis BaseExecutor
- Android Activity 生命周期
七、模板方法 VS 策略模式
- 模板方法:基于继承,固定流程骨架,步骤可变 → 一套流程,多种实现
- 策略模式:基于组合,算法可互换,平级替换 → 多套算法,自由切换
