# 实体与值对象（Entity & Value Object）

URL: https://caijiao.org/ddd/chapter2/entity-value-object
Source: docs/ddd/chapter2/entity-value-object.md
Description: 深入理解实体（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）               | 无唯一标识符                           |
| 可变性     | 状态可变                         | 状态不可变                             |
| 平等性     | 通过标识符判断平等               | 通过属性值判断平等                     |
| 适用场景   | 表示具有身份的对象，如客户、订单 | 表示描述性信息，如货币、地址、日期区间 |

## 实践建议

- 在设计领域模型时，如果对象具有唯一身份，并且在系统中有生命周期，应该设计为实体。
- 如果对象只是描述某些属性，且没有必要追踪身份，应该设计为值对象。
- 避免过度使用实体，尽可能将不需要身份标识的对象建模为值对象，以简化系统设计。

通过合理使用实体与值对象，你可以构建出更加简洁且具备高内聚、低耦合的领域模型。
