模板方法模式必须使用抽象类,因其需定义固定执行流程、封装共享状态、提供构造器校验及支持protected成员,而接口仅能声明行为契约,无法约束调用顺序或持有状态。

模板方法模式本质是“流程固定、细节可变”,它天然依赖抽象类来承载骨架逻辑。选接口还是抽象类,关键看你要约束的是“能做什么”,还是“怎么一步步做”。
当需要定义算法执行顺序时,必须用抽象类
接口只能声明行为契约,无法规定调用先后或封装共用流程。而模板方法的核心是一段 final 的 public 方法(如 execute()),内部按序调用若干钩子方法(init() → doWork() → cleanup())。这种控制流只能放在抽象类里——它既有具体实现能力,又能强制子类填充空白。
- 抽象类可含构造器、字段、具体方法和抽象方法,适合封装共享状态(如数据库连接池、日志上下文)和复用代码
- 子类只需重写抽象钩子,不碰流程逻辑,避免重复编写 if/try/finally 等样板
- 若改用接口,你得把 execute() 拆成多个独立方法,失去“一步触发整套流程”的语义
当存在公共状态或初始化逻辑时,抽象类更自然
比如一个报表导出系统,不同子类导出 PDF、Excel 或 CSV,但都需要统一的标题生成、数据过滤、异常记录。这些可放在抽象类的 protected 字段和具体方法中;接口无法定义字段,也无法提供默认初始化逻辑(Java 8+ default 方法不能调用 this.field)。
- 抽象类支持 protected 成员变量,子类可直接访问并复用(如缓存结果、配置参数)
- 构造器可用于校验必要参数,确保子类实例化前满足前提条件
- 接口只描述“有哪些操作”,不参与对象构建过程,也不持有状态
当未来可能扩展默认行为时,抽象类兼容性更好
版本迭代中,如果要在主流程里新增一个预处理步骤(如权限校验),在抽象类中加一个非抽象的钩子方法,并在模板方法中插入调用即可;所有已有子类自动继承该行为,无需修改。而接口一旦新增 default 方法,虽不强制实现,但若涉及状态变更或流程介入,往往仍需子类配合调整——它缺乏执行上下文的掌控力。
- 抽象类新增非抽象方法 = 向下兼容的增强
- 接口新增方法 = 所有实现类需显式响应(即使有 default,语义上也常需重写)
- 模板方法的“骨架”属性决定了它必须能随业务演进主动生长,而非被动响应契约
接口适合定义能力集合(如 Runnable、Comparable),抽象类适合定义角色与流程(如 HttpServlet、JdbcDaoSupport)。模板方法不是“要不要用抽象类”的问题,而是“只有抽象类才能真正实现它”的设计事实。

















