欢迎光临
我们一直在努力

【设计模式】行为型-模板方法模式

文章目录

  • 前言
  • 一、概念
  • 二、核心结构
  • 三、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;
    }
    }


    五、优缺点

    优点

  • 封装不变部分,扩展可变部分 流程固定不动,细节交给子类。
  • 代码复用极强 公共逻辑只写一次,子类只关注差异。
  • 符合开闭原则 新增流程只需加子类,不改模板。
  • 行为由父类控制,子类实现 结构清晰、易于维护。
  • 缺点

  • 类数量可能增多(每个不同实现一个子类)
  • 父类若出错,会影响所有子类
  • 过度使用会导致继承层次复杂

  • 六、应用场景

    凡是流程固定、个别步骤不同的场景:

  • 支付流程(微信/支付宝/银行卡)
  • 用户注册/登录流程
  • 数据导入/导出(Excel、CSV、XML)
  • 消息发送(短信、邮件、站内信)
  • 工作流审批(发起、审核、通过、驳回)
  • 经典源码应用:

    • Java Servlet doGet/doPost
    • Spring JdbcTemplate、RestTemplate
    • MyBatis BaseExecutor
    • Android Activity 生命周期

    七、模板方法 VS 策略模式

    • 模板方法:基于继承,固定流程骨架,步骤可变 → 一套流程,多种实现
    • 策略模式:基于组合,算法可互换,平级替换 → 多套算法,自由切换

    八、总结

  • 模板方法模式 = 固定流程骨架 + 可变步骤实现
  • 核心:父类定流程(final),子类填细节
  • 关键:模板方法 + 抽象方法 + 钩子方法
  • 最适合:流程固定、重复代码多、差异小的业务
  • 是企业级开发中复用率极高的行为型模式
  • 赞(0)
    未经允许不得转载:171主机测评 » 【设计模式】行为型-模板方法模式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址