扁平化继承树的关键是消除语义混乱与职责交叉,保留每层不可替代的语义价值;冗余层级应移除或转为接口,抽象类须聚焦单一职责且子类2–5个,行为能力用接口定义并辅以default方法,共性逻辑下沉为单一层级抽象类,策略型逻辑改用组合委托。

直接把深层继承树“砍掉”不是目的,关键是把语义混乱、职责交叉、复用错位的部分重新归位。扁平化不是去掉继承,而是让每层继承都有不可替代的语义价值,把行为契约和状态复用拆开处理。
识别并剥离冗余继承层级
先检查继承链中哪些类只是为“共享几个方法”而存在,而非真正表达“is-a”关系。比如:
Vehicle → Car → Sedan → ElectricSedan → TeslaModel3
其中 Sedan 和 ElectricSedan 很可能只是分类标签,不承载可复用的状态或算法骨架。这类中间层应被移除或转为接口。
- 用 IDE 的“查找所有子类”功能,确认某抽象类是否真有多个差异化实现;若仅有一个子类,大概率是过度设计
- 把仅含通用校验、日志、序列化逻辑的中间类,抽成工具类或默认方法接口(如
Loggable、Serializable) - 保留的抽象类必须满足:至少有两个子类需复用其字段或部分实现,且这些子类在业务上确实属于同一抽象维度
用接口定义正交能力,替代多维继承
深层继承常源于想同时表达“是什么”和“能做什么”,例如一个类既要表示“是报表”,又要表示“支持导出”“支持筛选”“可定时刷新”。这种多维度变化应交给接口,而不是堆叠继承。
- 将行为型能力声明为接口:
Exportable、Filterable、Schedulable - 具体类按需实现,避免为了“统一管理”而强行拉出
BaseReport去囊括所有能力 - 接口中用 default 方法提供基础实现(如
exportToExcel()),但不引入状态字段
将共性逻辑下沉为抽象类,但限制单一层级复用
抽象类适合封装有状态、有生命周期、有模板流程的共性。但它不应成为“万能父类”,而应聚焦单一职责维度。
- 例如,所有需要远程调用的组件可继承
AbstractRemoteService(含重试、熔断、traceId 注入),但不混入权限、缓存、日志等其他关注点 - 每个抽象类只解决一个问题,且子类数量建议控制在 2–5 个;超出说明抽象粒度太粗,需进一步切分
- 抽象类构造器中避免复杂初始化,把可配置项转为 protected final 字段或 builder 模式传入
用组合补足缺失的灵活性
当发现某个子类总要重写父类的某个方法来“绕过逻辑”,或频繁调用 super.xxx() 再加额外处理,说明那部分逻辑本不该在继承链里——它属于可插拔的行为。
- 把策略型逻辑(如数据加载、格式转换、权限校验)提取为独立组件,由主类持有并委托调用
- 例如:
ReportGenerator不再继承BaseExporter,而是持有一个ExporterStrategy实例 - 运行时可通过构造参数或 Spring Bean 注入不同策略,比编译期继承更易测试和替换











