核心是切断子类对父类实现的隐式绑定,继承仅表达“是一种”;限制继承深度为两层,基类只留契约不塞逻辑,用组合+接口替代能力继承,警惕并重构脆弱基类信号。

避免对基类的过度依赖,核心是切断子类对父类内部实现的隐式绑定,让继承回归语义本质——只表达“是一种”,不承担“怎么做到”。过度依赖往往表现为子类必须知道父类字段初始化顺序、protected方法调用时机、模板方法中钩子的执行边界等细节,稍有改动就崩溃。
限制继承深度,封禁多层派生
把继承树严格控制在最多两层:基类 → 具体实现类。中间抽象层(如ValidatedService、CachedService)极易演变成“补丁聚合器”,反而加剧耦合。
- 所有具体业务类声明为final,禁止被进一步继承
- 在CI流程中接入SonarQube规则java:S1118或自定义检查,自动拦截超过2层的继承链
- IDEA启用“Inheritance depth”提示,超深类标黄预警
基类只留契约,不塞逻辑
基类不是功能仓库,而是行为协议守门人。任何可变参数、默认策略、资源连接、异常包装,都不该写死在父类里。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- public方法尽量声明为final,仅开放少量protected abstract钩子(如doProcess())供核心逻辑定制
- 超时、重试次数、日志级别等全部通过构造函数或Builder注入,不设字段默认值
- 单元测试只验证流程顺序(before → doProcess → after),不测具体行为
用组合+接口替代“能力继承”
当发现子类只是为了复用某项能力(如日志、校验、缓存)而继承,说明这不是“is-a”,而是“has-a”。此时应剥离为独立组件。
立即学习“Java免费学习笔记(深入)”;
- 把LoggingService改为EventLogger接口 + 多个实现类(FileLogger、SlackLogger)
- 将校验逻辑抽成ValidationRule策略对象,构造时传入,而非继承固定校验骨架
- 业务类字段声明为接口类型,调用方只依赖契约,替换实现零代码修改
警惕脆弱基类信号,及时重构
这些是基类已被污染的明显征兆,需立即干预:
- 父类构造器里调用被子类重写的protected方法,引发NullPointerException
- 子类只重写1–2个方法,其余全靠父类“白给”,但又不敢动父类以防影响其他子类
- 类图中某个基类扇出(直接子类数)超过5个,且子类间行为高度雷同
- 大量子类存在空实现(@Override public void onInit() {})

















