优化Java继承的核心是分离“谁来干”和“怎么干”,用接口定义行为契约、组合替代继承、依赖注入解耦实现,仅在具备稳定骨架且不暴露业务契约时谨慎使用抽象基类。

Java 继承容易把类绑得太紧,改父类可能让一堆子类悄悄出错。优化核心不是“少用继承”,而是把“谁来干”和“怎么干”分开,让代码更松、更稳、更容易换。
用接口定义行为契约,不带状态
接口只声明“能做什么”,比如 PaymentProcessor 接口只写 process(PaymentRequest req),不放 timeoutMs 字段、不设构造器、不暴露 formatLog() 这类工具方法。这样实现类(如 AlipayProcessor、WechatProcessor)完全自主,互不影响。
- 避免在接口里加默认字段或 protected 方法,那会悄悄引入状态依赖
- 一个接口只聚焦一个职责:支付就只管支付,别混进日志、重试、限流
- 如果多个场景需要不同能力,就拆成多个小接口,比如 Refundable、Cancelable
优先组合,而不是层层继承
“狗是一个动物”听起来合理,但代码里往往只需要“狗有名字”“狗会叫”。与其让 Dog 继承 Animal,不如让它持有 NameHolder 和 SoundEmitter 实例——这样复用的是能力,不是整套骨架。
- 把通用逻辑抽成独立组件,通过成员变量引用,而非 extends
- 组合关系天然支持运行时替换(比如换一个 MockSoundEmitter 做测试)
- 继承树控制在两层以内,深层共性用接口(如 Identifiable)或工具类替代
依赖注入 + 接口类型声明
光有接口不够,关键在“谁来创建、谁来使用”。业务类里不能直接 new 实现类,字段和构造参数都得是接口类型。
立即学习“Java免费学习笔记(深入)”;
- Spring 中用
@Autowired private PaymentProcessor processor;,而不是new AlipayProcessor() - 手动管理时,用工厂方法返回接口实例,调用方只认接口,不关心具体是谁
- 这样换一种支付方式,只需改配置或工厂逻辑,业务代码一行不动
谨慎保留继承的几种情况
不是所有继承都要砍掉。当满足以下条件时,抽象基类仍有价值:
- 多个子类确有稳定不变的状态与算法骨架(比如统一处理 HTTP 重试、超时、Header 注入)
- 该基类本身不被外部直接依赖,也不实现任何业务接口
- 它的 public 方法全是 final,只留 protected 钩子供子类定制逻辑
- 真正的业务契约,仍由上层接口承担(如 HttpClient 接口)


















