值对象 (Value Object)
什么是值对象
值对象(Value Object,简称 VO 或 ValueObj) 用于表示没有唯一标识、仅由属性值定义其意义的对象。
只关心数据,不关心身份
值对象的特点
- 不可变性 创建后属性值不能修改,如需修改,应创建新的实例
- 值相等性 判断两个值对象是否相等,是比较所有属性值是否都相同,而非引用地址
- 可组合 值对象可以嵌套其他值对象
值对象可以有行为吗?
值对象可以有行为, 但是这些行为不能改变自身的状态,而是返回计算结果或返回新的值对象实例
值对象为什么要有行为?
如果没有行为,值对象就退化成“数据容器”(贫血模型),业务逻辑会散落到 Service 层
值对象常见合法行为类型
| 行为类型 | 示例 | 是否改变自身 |
|---|---|---|
| 查询/判断 | isValid(), isEmpty(), isAfter(date) | ❌ 否 |
| 计算/转换 | add(), toUSD(), nextDay() | ❌ 否(返回新对象) |
| 格式化 | toString(), formatAsLocal() | ❌ 否 |
| 比较 | compareTo(), equals() | ❌ 否 |
record是值对象的理想选择
Java 的 record 是为“不可变数据载体”而设计的,其特性完美匹配 DDD 值对象的要求
| 值对象要求 | record 是否满足 | 说明 |
|---|---|---|
| 不可变性 | ✅ 是 | 所有字段默认 private final,无 setter |
| 结构化相等(equals/hashCode) | ✅ 是 | 自动生成基于字段值的 equals() 和 hashCode() |
| 简洁性 | ✅ 是 | 一行代码定义完整类 |
| 透明访问 | ✅ 是 | 自动生成 public 的只读 accessor(如 amount()) |
| 可封装行为 | ✅ 是 | 可以添加方法(包括静态工厂、业务方法等) |