模板方法必须用抽象类,因为其需固化流程、定义已实现和抽象方法,并用final防止重写;接口无法满足这些要求,仅适合声明能力契约。

模板方法不能直接在接口中设计——接口本身不支持定义“算法骨架”这种带有执行顺序和流程控制的结构。真正承载模板方法的是抽象类,接口只适合声明能力契约。
为什么模板方法必须用抽象类
模板方法的核心是:把不变的流程(如校验、预处理、后处理)固化在父类里,把可变的部分(如具体执行逻辑)留给子类实现。这需要三个关键支撑:
- 能定义非抽象的、已实现的方法(比如 validate()、postProcess())
- 能定义抽象方法强制子类实现(比如 executePayment())
- 能用final 修饰模板方法本身,防止子类破坏流程顺序
而接口在 JDK 8 之前只能有抽象方法;即使现在支持 default 和 static 方法,它仍无法满足上述全部条件——接口不能有构造器、不能保存状态、不能限制子类重写某个方法(default 方法可被任意重写)、也不支持 final 方法。
标准模板方法结构(抽象类实现)
以支付为例,一个典型的抽象模板类长这样:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 定义一个 public final void processPayment(double amount) 模板方法,内部按序调用 validate → preProcess → executePayment → postProcess
- 其中 executePayment() 声明为 protected abstract,由 AlipayProcessor、WechatProcessor 等子类各自实现
- validate() 和 postProcess() 是已实现的具体方法,所有子类自动复用
- 子类只需关注自己独有的那一步,其余流程零重复、零遗漏
接口如何配合模板方法使用
接口不替代模板方法,但可以与之协同,提升系统扩展性:
- 用接口定义顶层能力,比如 PaymentProcessor 接口声明 process() 和 refund(),作为统一类型引用
- 让抽象类实现该接口,例如 abstract class AbstractPaymentProcessor implements PaymentProcessor
- 具体子类继承抽象类的同时,天然满足接口契约,既获得流程复用,又支持面向接口编程
- 后续新增支付方式时,只需写新子类,无需改动调用方代码,也不影响现有流程
别踩的坑:混淆契约与流程
常见误用包括:
- 把本该是能力描述的接口(如 Flyable、Printable)强行改成抽象类,导致子类被迫继承无关字段或初始化逻辑
- 在接口里堆砌大量 default 方法来模拟流程,结果逻辑耦合、状态难管、测试困难
- 抽象类中塞太多 final 方法,把钩子点堵死,反而丧失子类定制空间
记住:接口回答“能做什么”,抽象类回答“怎么做才一致”。模板方法属于后者,它的根必须扎在抽象类里。

















