变量契约由责任归属决定而非字段声明,接口仅声明能力不管理状态,抽象类才是封装共享字段、初始化逻辑和配置参数的合理载体。

变量契约不是靠“声明字段”来约定的,而是靠“谁负责持有、谁有权修改、谁需要共享”来决定的。接口不能承载变量契约,抽象类才是管理共享状态的合理载体。
接口不管理变量,只声明能力
接口里不能定义实例字段——哪怕写 String seat;,编译器也会强制你改成 public static final String seat = "default";。这不是语法限制,而是设计语义:接口回答“能做什么”,不回答“有什么”。
所以,像 topSpeed、wheelDiameter、gears 这类每个对象独有、可变、需子类差异化赋值的状态,绝不能放在接口里。
抽象类是变量契约的落地位置
当你发现多个子类反复声明相同字段、重复初始化逻辑、或共用配置参数时,就该把它们提到抽象类中:
- 用
protected字段暴露共享状态(如protected String seat;),子类可直接访问、覆写、扩展 - 在构造方法中统一约束初始化流程(如强制传入
wheelDiameter和gears) - 配合
final字段封装不可变配置(如protected final int MAX_GEAR = 27;) - 通过
getXXX()模板方法统一暴露状态,同时保留子类定制权
变量 + 行为混合建模时的协同结构
真实业务模型往往既有共享字段,又需横向拼接能力。这时应分层设计:
- 先定义接口声明行为契约(如
Trackable、Refundable),确保不同实体可被统一调度 - 再用抽象类封装身份共性(如
AbstractOrder含orderNo、createdAt、status等字段和通用校验) - 最终具体类
extends AbstractOrder implements Trackable, Refundable,既继承状态骨架,又获得能力组合
识别变量契约是否被错误建模的信号
当出现以下情况,说明变量契约选型出错:
- 多个实现类中,
private String seat;几乎一模一样,但无法复用 - 想统一修改某个字段的默认值,却要改十几个类
- 单元测试中反复 mock 相同字段的 getter,却找不到统一注入点
- 新增一个子类时,第一件事是复制粘贴五六个字段声明

















