抽象类可实现接口部分方法以分离通用与差异化逻辑,如在abstractorderprocessor中默认实现validate()和notify(),子类专注execute()和rollback();配合模板方法模式封装固定流程,用protected抽象或钩子方法隔离可变部分;相比接口default方法,抽象类支持实例状态、字段和protected工具方法,适合业务上下文和资源管理场景;需谨慎提取已验证重复且稳定的逻辑,预留before/after钩子、protected常量及策略注入等扩展点,并确保默认实现具备null安全、异常传播和并发健壮性。

抽象类可以实现接口的部分方法,让子类只关注自己真正需要定制的逻辑,这是非常实用的设计技巧。关键在于合理划分“通用行为”和“差异化行为”,把稳定、可复用的实现放在抽象类里,把易变、业务相关的逻辑留给子类去覆盖。
明确接口职责,拆分可复用逻辑
当一个接口定义了多个方法,但其中某些方法在多数场景下行为相似(比如日志记录、参数校验、结果包装),就可以把这些共性抽出来,在抽象类中提供默认实现。子类只需继承该抽象类,按需重写其余方法即可。
- 例如接口 OrderProcessor 包含
validate()、execute()、notify()、rollback()四个方法,其中validate()和notify()在大多数订单类型中都走统一校验规则和消息推送通道,就可在抽象类 AbstractOrderProcessor 中实现它们 - 子类如
PromotionOrderProcessor或RefundOrderProcessor只需专注实现execute()和rollback()即可
用模板方法模式封装流程骨架
如果接口方法之间存在固定执行顺序(比如“校验→处理→通知→记录”),可在抽象类中定义一个 final 的模板方法,调用若干 protected abstract 或 protected 方法,把可变部分隔离出来。
- 模板方法本身不被子类重写,保证流程一致性
- 子类通过实现抽象钩子方法(如
doExecute())或覆写默认方法(如afterNotify())来插入定制逻辑 - 这样既满足接口契约,又避免每个子类重复编写流程控制代码
谨慎使用默认方法 vs 抽象类实现
Java 8+ 接口支持 default 方法,但它不适合替代抽象类的这种设计:default 方法无法访问实例状态,也不能强制子类继承共同父类。若逻辑依赖字段、构造器初始化、或需要共享 protected 工具方法,必须用抽象类实现。
- 接口 default 方法适合无状态、纯工具性行为(如集合转换、简单判空)
- 涉及业务上下文、资源管理、或需要子类复用同一份缓存/配置时,抽象类是更自然的选择
- 二者可共存:接口声明 contract,抽象类提供带状态的默认实现,子类按需继承
预留扩展点,避免过度设计
不要为了“看起来整洁”而把所有方法都塞进抽象类。只提取那些已被验证为重复、且短期内不太可能变化的逻辑。留出清晰的扩展口,比如:
- 提供
beforeExecute()/afterExecute()空钩子方法,方便子类插入手动干预 - 将硬编码值转为受保护的
protected final常量或可被子类重写的 getter - 对可能分库分表、多渠道适配的逻辑,用策略对象注入而非直接实现,保持抽象类轻量
不复杂但容易忽略的是:抽象类里的默认实现要经得起单元测试,尤其注意 null 安全、异常传播和并发场景。一旦放出去,修改成本远高于接口 default 方法。









