抽象类复用公共代码的关键是精准拆分流程:稳定逻辑写为普通方法,差异点定义为abstract方法;模板方法用public final封装流程,强制子类实现核心动作,复用校验、日志等通用逻辑,并通过protected字段共享状态。

抽象类复用公共业务代码的关键,在于把稳定不变的逻辑写成普通方法,把必须差异化的地方留作抽象方法——不是靠“多写抽象方法”,而是靠“精准拆分流程”。
明确哪些逻辑该复用,哪些必须由子类决定
一个支付流程里,“校验订单”“记录日志”通常是通用动作,而“调用哪个渠道付款”是业务差异点。前者写成普通方法,后者定义为 abstract 方法。
- 必须复用的:参数校验、日志打印、事务开启/提交、统一异常包装
- 必须子类实现的:核心业务动作(如 doPay、calculateTax、notifyThirdParty)
- 可选扩展的:用 protected 钩子方法(如 beforeSubmit()、afterSuccess()),空实现,子类按需覆盖
模板方法模式是标准实践方式
把整个流程封装在 final 的模板方法中,保证执行顺序不被破坏,同时控制子类只能改“可变点”。
- 模板方法本身用 public final 修饰,禁止子类重写
- 每个步骤拆解为 protected 方法:抽象方法(强制实现)、普通方法(默认行为)、钩子方法(空实现)
- 例如:
public final void execute() { validate(); process(); notify(); },其中process()是 abstract,validate()和notify()是普通方法
利用构造器和字段共享状态,避免重复初始化
抽象类可以声明实例字段(如配置对象、工具类引用),并在构造器中完成初始化,子类通过 super() 直接复用。
- 字段建议用 protected 修饰,便于子类访问但不暴露给外部
- 构造器中只做轻量初始化,避免调用可能被重写的方法(防止 this 引用逸出)
- 比如:抽象类持有
protected final OrderService orderService;,子类无需再 new 或注入
避免常见设计陷阱
复用失效往往不是因为没写,而是因为结构错位。
- 不要把能复用的逻辑硬拆成 abstract 方法,强迫子类写一堆 return null 或空实现
- 不要在抽象类里放无意义的抽象方法——如果某个方法所有子类都用同一段代码,它就不该是 abstract
- 接口更适合定义契约,抽象类更适合带状态、有构造逻辑、需复用具体实现的场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











