多层抽象类设计应围绕“行为契约”与“能力分层”,顶层定义流程骨架(如prepare/execute/cleanup),中层封装共性逻辑(如计时、日志),下层专注业务实现;需避免硬编码配置、技术栈细节和业务分支混入抽象层,并用final方法锁定主流程,辅以钩子方法提升灵活性。

多层抽象类设计不是堆砌层级,而是围绕“行为契约”与“能力分层”做有目的的抽象。核心在于:上层定义流程骨架,中层封装共性逻辑,下层聚焦具体实现。模板化不是把所有代码塞进 abstract class,而是让每个抽象层只承担它该管的事。
明确每层抽象的职责边界
三层结构常见分工:
-
顶层抽象类(如
TaskTemplate):只声明不可变流程骨架和必须实现的核心动作,比如prepare()、execute()、cleanup(),不提供任何具体实现; -
中间抽象类(如
TimedTask):继承顶层,复用并增强通用能力,例如自动注入计时逻辑、日志记录、异常兜底,同时可选择性提供默认prepare()或cleanup()实现; -
具体子类(如
DataImportTask、ReportGenerationTask):只专注业务逻辑本身,重写真正差异化的execute(),其余由父层自动保障。
避免抽象污染:哪些不该放进抽象层
以下内容一旦混入抽象类,就会削弱模板价值:
- 硬编码的配置值(如超时毫秒数、重试次数)——应通过构造参数或依赖注入传入;
- 特定技术栈细节(如
JdbcTemplate或RestTemplate的调用)——属于实现层,抽象层只定义“如何获取数据”,不规定“用什么取”; - 业务判断分支(如 “如果是订单类型 A 就走 X 流程”)——这属于策略模式范畴,应抽离为独立策略类,而非在抽象类里 if-else。
用 final 方法锁定模板流程
防止子类意外破坏执行顺序,关键流程方法应设为 final:
示例:
public abstract class TaskTemplate {
public final void run() {
prepare();
long start = System.currentTimeMillis();
execute();
long end = System.currentTimeMillis();
logExecutionTime(end - start);
cleanup();
}
protected abstract void prepare();
protected abstract void execute();
protected abstract void cleanup();
private void logExecutionTime(long ms) { /* 统一日志格式 */ }
}
这样,无论子类怎么重写 execute(),计时、日志、前后置动作都始终受控。
配合钩子方法(Hook Method)提升灵活性
在流程骨架中预留可选扩展点,比强制重写更轻量:
- 定义
protected void onBeforeExecute() { }这类空实现的 hook 方法; - 子类按需覆盖,无需改动主流程;
- 比抽象方法更友好,避免子类因遗漏实现而编译失败。











