主题
实体与值对象(Entity & Value Object)
在领域驱动设计(DDD)中,实体(Entity) 和 值对象(Value Object) 是构建领域模型的两种核心元素。理解它们的区别和使用场景,能够帮助开发人员更加准确地建模业务需求。
实体(Entity)
定义
实体是具有唯一标识的对象,它们在系统的生命周期中可能会经历状态变化。实体的生命周期不依赖于它的属性,而是由它的唯一标识符(ID)决定。
特征
- 唯一标识符(ID):实体通过唯一的标识符来区分其他实体,即使它的属性发生变化,其标识符仍然保持不变。
- 生命周期:实体有自己的生命周期,通常由创建、变更和删除组成。
- 可变性:实体的状态是可变的,可以通过操作方法或领域事件进行修改。
示例
java
public class Customer {
private final String customerId;
private String name;
private String email;
public Customer(String customerId, String name, String email) {
this.customerId = customerId;
this.name = name;
this.email = email;
}
public String getCustomerId() {
return customerId;
}
public void updateEmail(String newEmail) {
this.email = newEmail;
}
}
何时使用实体?
当你需要跟踪一个对象的身份,并且该对象的属性可能会发生变化时,使用实体。例如,客户、订单、用户等,都是具有唯一标识的实体。
值对象(Value Object)
定义
值对象没有唯一标识符,它们仅通过属性值来区分。值对象通常是不可变的,创建后不能更改其状态。值对象是描述对象属性的一种方式,可以通过其属性来定义其值。
特征
- 无唯一标识符:值对象没有唯一标识符,它们的身份由其属性的值决定。
- 不可变性:值对象创建后,其属性值不能被修改。任何修改值对象的操作,都会返回一个新的值对象。
- 平等性:值对象的平等性通常是通过其属性值来判断的。
示例
java
public class Money {
private final BigDecimal amount;
private final String currency;
public Money(BigDecimal amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Currencies must match.");
}
return new Money(this.amount.add(other.amount), this.currency);
}
}
何时使用值对象?
当你需要描述对象的某些属性而不关心对象的身份时,使用值对象。例如,地址、货币金额、日期区间等,都是典型的值对象。
实体与值对象的区别
特性 | 实体(Entity) | 值对象(Value Object) |
---|---|---|
唯一标识符 | 有唯一标识符(ID) | 无唯一标识符 |
可变性 | 状态可变 | 状态不可变 |
平等性 | 通过标识符判断平等 | 通过属性值判断平等 |
适用场景 | 表示具有身份的对象,如客户、订单 | 表示描述性信息,如货币、地址、日期区间 |
实践建议
- 在设计领域模型时,如果对象具有唯一身份,并且在系统中有生命周期,应该设计为实体。
- 如果对象只是描述某些属性,且没有必要追踪身份,应该设计为值对象。
- 避免过度使用实体,尽可能将不需要身份标识的对象建模为值对象,以简化系统设计。
通过合理使用实体与值对象,你可以构建出更加简洁且具备高内聚、低耦合的领域模型。