接口继承旨在组合正交行为契约、明确能力边界,变量逻辑由实现类通过构造注入或策略模式自然落地,避免深继承链,default方法仅用于无状态通用逻辑。

接口继承不是为了复用代码,而是为了组合行为契约、明确能力边界,并让变量逻辑(比如状态管理、配置注入)在实现层自然落地。关键不在“怎么写继承语句”,而在“哪些行为该归到同一层契约里”。
用多接口继承表达正交职责
一个业务对象常具备多个独立维度的能力,比如订单既要可支付、又要可取消、还要可追踪物流。这些不是父子关系,而是并列契约:
- 定义 PaymentCapable 接口:只含
pay()和refund() - 定义 CancellationCapable 接口:只含
cancel()和reasonForCancellation() - 定义 TrackingCapable 接口:只含
getTrackingNumber()和checkStatus() - 再声明 OrderBehavior extends PaymentCapable, CancellationCapable, TrackingCapable —— 它不新增方法,只是把三组能力打包成一个语义清晰的契约名
这样做的好处是:调用方能按需选择契约类型(如通知服务只需 TrackingCapable),而具体类如 OnlineOrder 可以选择性实现部分接口,不必为不相关能力留空桩。
变量逻辑交给实现类,接口只管“能做什么”
接口中不能有字段,也不该试图封装变量行为。但变量逻辑(比如重试次数、超时阈值、日志级别)可以通过以下方式自然整合:
- 在实现类中定义
private final int maxRetries = 3;,并在对应方法里使用它 - 通过构造函数或依赖注入传入配置对象(如
RetryPolicy),保持接口方法签名干净 - 若多个实现共用同一套变量规则,可提取为工具类或策略接口(如
RetryStrategy),由实现类持有并委托调用
例如 AlipayPayment implements PaymentCapable 内部持有一个 HttpRetryer 实例,它本身实现了 RetryStrategy 接口——变量逻辑被隔离、可测试、可替换,而 PaymentCapable 依然只承诺“我能付钱”,不暴露怎么付。
避免继承链过深,用组合代替隐式义务
接口继承不是越深越好。像 A extends B, C; B extends D, E; C extends F 这种嵌套会让实现类被迫承担大量间接契约,稍有遗漏就编译失败,且难以追溯责任归属。
- 推荐扁平化设计:基础接口(如
Serializable,Loggable)直接被业务接口继承,不设中间层 - 当某组方法总是一起出现,考虑是否该合并为一个新接口,而不是靠继承拼凑
- 如果发现两个接口总被同一类同时实现(如
UserService implements UserRepository, PasswordEncoder),说明它们可能本就属于同一领域契约,值得重构为统一接口
真正需要的是“契约清晰”,不是“继承层数好看”。一个接口名能让人一眼看懂它代表什么能力,比五层继承更有价值。
default 方法用于共享无状态逻辑,不带变量副作用
Java 8+ 的 default 方法适合封装通用、无副作用的行为,比如格式化、校验前置逻辑、空值保护等:
default String toSafeId() { return Optional.ofNullable(id).map(String::valueOf).orElse("unknown"); }- 但不要在里面操作成员变量、发起网络请求、或修改外部状态
- 如果逻辑涉及变量(如重试计数器、缓存容器),必须由实现类自己管理,default 方法只提供模板骨架
这样既避免重复编码,又守住接口“不绑定实现”的底线——变量逻辑始终可控、可测、可替换。










