继承树设计核心是职责清晰与变化隔离,优先组合代替继承,限制深度至两层以内并确保每层语义明确。

继承树设计不是为了“多继承”或“深继承”,而是让复用真正有用、改动真正可控。关键不在层级多不多,而在每个父类是否职责清晰、变化是否隔离。
只让真正共有的行为上移
把多个子类都有的字段和方法,才放进父类。如果某个子类后续需要改逻辑,而其他子类不需要,说明它不该在父类里——宁可重复两行代码,也不要把不稳定的逻辑强塞进继承链。
比如用户类和订单类都有“创建时间”,可以提取;但“用户有头像URL”和“订单有收货地址”就该各自保留在子类中,强行抽象成父类字段只会导致空值判断和类型转换问题。
优先用组合代替继承
当两个类只是“用到”某部分能力,而不是“是一种”,就别用继承。比如日志记录、缓存操作、权限校验这些通用能力,更适合封装成独立对象,由具体业务类持有并调用。
- 父类膨胀后,子类被迫继承一堆无关方法,接口污染严重
- 继承关系一旦确立,修改父类会影响所有子类,风险集中
- 组合方式能随时替换实现(如换 Redis 缓存为 Caffeine),继承做不到
抽象类比接口更需谨慎
抽象类带实现,复用性强,但也意味着耦合更深。除非多个子类确实共享同一套流程骨架(比如报表生成:收集→格式化→导出),否则优先用接口定义契约,让子类自由实现。
若必须用抽象类,把可变部分声明为 abstract 方法,把稳定部分(如统一异常包装、日志打点)放在 final 方法里,避免子类误重写关键流程。
限制继承深度,明确每层语义
超过三层的继承链很难维护。建议控制在两层以内:顶层是领域概念(如 PaymentMethod),中间层是技术分类(如 OnlinePayment),叶子层才是具体实现(如 WechatPay、Alipay)。
每层命名要体现差异,不能叫 BaseService → CommonService → UserService 这种无信息量的命名。语义模糊的父类,就是耦合的温床。

















