1. Eric Evans DDD 蓝皮书的实体(Entity)与值对象(Value Object)的核心差异中身份 vs 属性
请解释 Eric Evans 在 DDD 蓝皮书中定义的实体(Entity)与值对象(Value Object)的核心差异,并说明"身份 vs 属性"这一判定的具体含义?
- 实体与值对象在"身份标识"上的本质区别
- 判定一个对象是实体还是值对象的依据
- 实体与值对象在生命周期、可变性、相等性上的差异
核心差异在于"身份"(identity)与"属性"(attribute)的定位。实体具有贯穿其生命周期的连续身份标识,即便它的属性全部改变,只要身份不变,它就是同一个对象。例如一个订单(Order)即使改了状态、金额、收货地址,它仍然是同一个订单,靠订单号(orderId)识别。值对象则没有独立的身份,它由一组属性值定义,一旦属性值改变,它就变成了另一个值对象。例如地址(Address)由省、市、街道构成,改变任何属性就得到另一个地址,没有"同一性"可言。在判定上,问题问的是"这个对象有身份吗?它会在生命周期中变化吗?它是被复制还是被区分?"——需要跟踪身份、有生命周期的用实体;仅描述属性、内部属性整体才有意义、可被替换的用值对象。值对象通常不可变,两个值对象相等与否取决于全部属性值是否相等,而实体相等仅取决于身份标识。
选择实体还是值对象直接影响设计质量。把没有身份的对象当实体处理会引入不必要的 ID 和可变状态,增加复杂度;把有身份的对象当值对象处理则会丢失身份标识,导致无法追踪。蓝皮书强调"身份判断"是建模的第一步,多数领域模型中的"小对象"(金额、时间范围、地址、颜色)都应是值对象。
// 实体:身份相同即同一对象
public class Order {
private final OrderId id; // 身份标识
private OrderStatus status;
// 属性改变,但身份不变
}
// 值对象:无身份,全部属性构成其值
public final class Address {
private final String street;
private final String city;
// 没有 id,属性相等即对象相等
}