导读:本期聚焦于小伙伴创作的《如何实现Java的模板方法模式?抽象类在流程控制中该怎么用》,敬请观看详情。把不变的执行流程固守在抽象类、把易变的具体步骤下放给子类,是模板方法模式解决代码复用的核心思路。不少团队在写报表导出、订单审批时重复堆砌相似逻辑,其实只需定义一个含final模板函数的抽象类,将校验、执行、收尾等步骤声明为抽象或钩子方法,子类重写局部实现即可。该方式利用Java继承机制约束调用顺序,避免子类破坏主流程,同时借助钩子方法留有扩展余地。文中以支付清算为例,给出抽象类骨架与子类落地代码,并分析比起策略模式它更擅长控制整体节奏而非替换算法。

模板方法模式属于行为型设计模式,它在一个抽象类中定义算法的骨架,将某些步骤延迟到子类实现。在Java里,这种控制力主要来自抽象类与final方法的配合:父类把流程顺序锁死,子类只能填充细节,从而既保证一致性又减少重复代码。

如何实现Java的模板方法模式?抽象类在流程控制中该怎么用

一、模板方法模式的基本结构

模板方法模式包含两种角色。一是抽象类,它声明模板方法(通常用final修饰)以及若干基本方法,基本方法可以是抽象方法、具体方法或钩子方法。二是具体子类,它继承抽象类并实现其中的抽象方法,或覆盖钩子方法以影响流程分支。

之所以使用抽象类而不是接口,是因为Java接口在JDK 8之前不能有方法体,难以承载固定的流程代码。抽象类允许我们写出通用的前置处理、后置处理逻辑,只在关键节点调用子类方法。这种“父类调用子类”的反向控制,正是框架常用的好莱坞原则:别调用我们,我们会调用你。

1.1 抽象类中的方法分类

抽象方法:强制子类提供实现,例如do_parse()。具体方法:父类已写好,子类直接复用,如日志记录。钩子方法:父类提供空实现或默认返回true,子类可选择性覆盖,用来干预流程,例如need_validate()

合理搭配这三种方法,可以让模板既稳定又灵活。如果所有步骤都是抽象方法,子类负担过重;如果全是具体方法,则失去扩展意义。实际项目中多以一个final模板方法串联多个钩子与抽象方法。

二、抽象类在流程控制中的应用示例

下面以支付清算为例。每日批处理需要先加载数据、再做校验、执行清算、最后归档。这个顺序绝不能乱,因此我们把顺序写在抽象类的final方法中,把校验规则和清算方式留给不同渠道子类。

public abstract class AbstractSettlement {
    // 模板方法,禁止子类修改顺序
    public final void process(String date) {
        loadData(date);
        if (needValidate()) {
            validate();
        }
        settle();
        archive();
    }

    private void loadData(String date) {
        System.out.println("加载" + date + "交易数据");
    }

    // 钩子方法,默认需要校验
    protected boolean needValidate() {
        return true;
    }

    protected abstract void validate();

    protected abstract void settle();

    private void archive() {
        System.out.println("归档并完成记账");
    }
}

上述代码中,process是模板方法,用final修饰以防子类重写破坏流程。needValidate是钩子,子类可返回false跳过校验。validatesettle是抽象方法,由子类完成。

接着写两个具体子类,分别处理银行卡与第三方钱包渠道。它们只关心自己特有的校验与清算规则,不必重复写加载和归档。

public class BankCardSettlement extends AbstractSettlement {
    @Override
    protected void validate() {
        System.out.println("校验银行卡交易签名");
    }

    @Override
    protected void settle() {
        System.out.println("调用核心系统完成借记");
    }
}

public class WalletSettlement extends AbstractSettlement {
    @Override
    protected boolean needValidate() {
        return false; // 钱包内部已验签,跳过
    }

    @Override
    protected void validate() {
        // 不会被执行
    }

    @Override
    protected void settle() {
        System.out.println("更新钱包余额账务");
    }
}

2.1 客户端调用方式

调用方只需面向抽象类编程,根据配置选择子类。这样新增渠道时,只需增加子类,不动原有流程。

public class Client {
    public static void main(String[] args) {
        AbstractSettlement s1 = new BankCardSettlement();
        s1.process("20240101");

        AbstractSettlement s2 = new WalletSettlement();
        s2.process("20240101");
    }
}

从输出可以看到,两个子类的加载与归档逻辑完全一致,差异只在校验与清算。抽象类在此承担了流程守门员的职责。

三、与策略模式的区别及适用场景

初学者常把模板方法模式和策略模式混淆。策略模式是把整个算法替换掉,通过组合不同策略对象来改变行为;模板方法模式是算法骨架不变,仅替换其中部分步骤,且依赖继承而非组合。

当你需要控制多个步骤的执行次序、并复用大量公共前置后置代码时,模板方法更合适。例如各类批处理、流水线作业、框架的初始化生命周期。若只是单一算法可互换,如排序方式、折扣计算,则策略模式更轻量。

3.1 优缺点分析

优点在于代码复用率高、流程统一可控、符合开闭原则。缺点是父类与子类耦合较强,子类受制于父类结构;如果继承层级过深,调试时调用栈不够直观。

在大型系统里,建议把模板方法限制在单一抽象层,不要在子类中再派生孙子类去改流程,否则容易违背单一职责。配合Spring等容器,也可把子类声明为Bean,由工厂注入,缓解硬编码问题。

四、在抽象类中运用钩子增强灵活性

钩子方法常被忽略,但它是模板方法模式避免僵化的关键。通过返回布尔值或空实现,父类可询问子类“要不要做某步”“做完某步后是否追加处理”。

protected void afterSettle() {
    // 空钩子,子类可覆盖发通知
}

在模板方法末尾调用afterSettle(),默认什么都不做。若某渠道清算后需推送短信,只需覆盖该方法。这样既不强迫所有子类实现,也保留了扩展点。

总结来说,Java模板方法模式借助抽象类的final方法与继承机制,把流程控制权保留在父类,把可变逻辑下放子类。只要分清抽象方法、具体方法与钩子方法,就能写出既规范又易维护的业务骨架。

模板方法模式抽象类Java流程控制修改时间:2026-08-02 07:06:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。