# 需求分析与领域建模

URL: https://caijiao.org/ddd/chapter5/domain-modeling
Source: docs/ddd/chapter5/domain-modeling.md
Description: 介绍如何进行需求分析与领域建模，确保在开发过程中能准确地捕捉业务需求并转化为领域模型。

在领域驱动设计（DDD）中，需求分析与领域建模是非常重要的步骤，它们帮助我们从复杂的业务需求中提取出核心的业务概念，并将这些概念转化为能够在代码中实现的领域模型。有效的需求分析与领域建模能够确保开发团队与业务团队之间的沟通顺畅，且最终产品能准确地解决业务问题。

## 1. 需求分析

需求分析的目的是深入了解业务需求、业务流程和系统的期望行为，以便构建出能够满足这些需求的领域模型。需求分析不仅仅是从技术角度的功能拆解，更是从业务角度对核心问题的理解。

### 1.1. 与业务团队的合作

需求分析首先需要与业务专家（如产品经理、业务分析师）密切合作，了解他们的需求。沟通时，可以使用以下几种方法：

- **用户访谈**：直接与业务人员或最终用户交流，理解他们的需求和痛点。
- **需求文档**：通过产品文档、功能需求文档等了解已明确的业务需求。
- **业务流程图**：通过绘制业务流程图（如 BPMN）来明确业务流程和各个环节。
- **用例分析**：通过用例图和用例描述，理清系统的主要功能和用户行为。

### 1.2. 聚焦业务核心

在需求分析时，重要的是要识别出核心的业务问题和关键领域。这些核心问题往往决定了项目的业务价值和功能优先级。通常，我们要通过与业务人员的多次交流和讨论，找到以下关键点：

- 领域内的核心概念：如产品、订单、支付等。
- 领域中的核心规则：如订单状态转换、支付成功条件等。
- 与外部系统的交互：如与支付网关、第三方物流的集成。

## 2. 领域建模

领域建模的目标是将从需求分析中获得的业务概念转化为代码中的领域模型。领域模型是对业务世界的抽象，通常包括实体（Entity）、值对象（Value Object）、聚合（Aggregate）等核心元素。领域模型是系统中最重要的组成部分，它应该准确表达出业务的本质。

### 2.1. 定义实体（Entity）与值对象（Value Object）

#### 实体（Entity）

实体是具有唯一标识的业务对象，通常会有生命周期，并且可能会在生命周期中改变属性。实体的生命周期与其标识息息相关，实体的身份是其最重要的特征。

例如，假设我们正在开发一个电商平台，订单（Order）就是一个实体，它有唯一的标识（例如订单 ID），并且随着时间的推移会有状态的变化。

```java
public class Order {
    private Long id;
    private OrderStatus status;
    private Customer customer;
    private List<OrderItem> items;

    public void addItem(OrderItem item) {
        items.add(item);
    }
}
```

#### 值对象（Value Object）

值对象是没有身份的对象，它的生命周期通常由其属性决定。当值对象的属性改变时，它通常会被视为一个新的对象。值对象是不可变的，一旦创建后，它的属性不会再发生变化。

例如，`Money` 可以作为一个值对象，它表示一个金额和币种，且一旦创建后，金额和币种就不可修改。

```java
public class Money {
    private BigDecimal amount;
    private Currency currency;

    // 不可变对象，属性一旦设置不能修改
}
```

### 2.2. 定义聚合（Aggregate）

聚合是由一个或多个实体和值对象构成的业务概念，它是领域模型中的一个重要构建块。聚合有一个聚合根（Aggregate Root），它负责管理聚合内其他实体和值对象的生命周期，并提供对外的访问接口。聚合根是聚合的入口，任何操作都应该通过聚合根来进行。

在电商系统中，`Order` 聚合可能包含多个 `OrderItem`，而 `Order` 就是聚合根。

```java
public class Order {
    private Long id;
    private List<OrderItem> items;

    public void addItem(OrderItem item) {
        items.add(item);
    }

    // 聚合根：Order
}
```

### 2.3. 领域服务（Domain Service）

领域服务是实现复杂业务逻辑的服务，通常涉及多个实体之间的协作。领域服务并不直接属于某个特定的实体，而是处理跨越多个实体的业务逻辑。

例如，在电商系统中，支付服务可能是一个领域服务，它处理订单支付逻辑，涉及多个领域对象（如 `Order`、`Payment` 等）。

```java
public class PaymentService {
    public void processPayment(Order order, Payment payment) {
        // 支付处理逻辑
    }
}
```

### 2.4. 确定领域事件（Domain Event）

领域事件用于表示某个重要业务行为的发生，通常是模型中不可变的事件。领域事件用于解耦不同聚合之间的逻辑，比如当一个订单被创建时，可以发布一个“订单已创建”的事件，这个事件可以触发其他系统的行为。

```java
public class OrderCreatedEvent {
    private Long orderId;

    // 事件发布
}
```

## 3. 领域建模的关键要点

在进行领域建模时，有几个要点需要特别关注：

- **反映业务规则**：领域模型的设计应尽量反映出业务规则，而不仅仅是数据的存取。每个聚合、实体和值对象都应当设计成能够表示业务中的核心概念和行为。
- **避免模型贫血**：模型贫血是指领域模型没有包含业务行为，只有数据属性。这会导致业务逻辑分散在服务层或控制器中，增加系统的复杂度。应尽量让领域模型包含更多的业务行为。
- **领域模型与技术实现分离**：领域模型应尽量保持与技术实现的独立性，不要让技术框架或数据库设计直接影响到业务模型。

## 4. 领域建模的实践

在实际的领域建模过程中，我们可以遵循以下步骤：

1. **识别关键业务实体**：通过需求分析，确定业务中的核心实体，如订单、用户、支付等。
2. **定义实体的行为**：在每个实体中加入必要的业务行为，而不仅仅是存储数据。
3. **确定聚合与聚合根**：根据业务需求，将相关的实体和值对象组织成聚合，并指定聚合根。
4. **建模领域服务**：对于复杂的业务逻辑，创建领域服务来协调多个实体之间的交互。
5. **定义领域事件**：在业务行为发生时，发布相应的领域事件，以便触发其他系统的操作。

## 5. 总结

需求分析和领域建模是领域驱动设计的核心部分，它们帮助开发者从业务角度出发构建出能够准确解决问题的领域模型。通过与业务团队密切合作，深入理解业务需求，再通过领域建模将这些需求转化为代码中的核心构件，能够确保系统的高内聚与低耦合，最终实现业务目标。
