# 基础设施与领域解耦

URL: https://caijiao.org/ddd/chapter5/infrastructure-decoupling
Source: docs/ddd/chapter5/infrastructure-decoupling.md
Description: 探讨如何将领域层与基础设施层解耦，以保证领域模型的纯粹性与可维护性。

在领域驱动设计（DDD）中，基础设施层和领域层之间的解耦是实现系统灵活性和可扩展性的重要原则之一。领域层应该专注于业务逻辑的实现，而不应该直接依赖于具体的基础设施实现。通过这种解耦，我们可以保持领域模型的独立性，从而更容易进行测试、维护和扩展。

## 基础设施层与领域层的关系

基础设施层负责与外部资源进行交互，例如数据库、消息队列、文件存储等。而领域层则包含了业务逻辑和领域模型。为了确保领域层不依赖于基础设施层，我们通常会通过以下几种方法来解耦：

- **依赖倒置原则（Dependency Inversion Principle）**：高层模块（领域层）不应该依赖于低层模块（基础设施层），两者应该依赖于抽象接口。
- **接口与实现分离**：基础设施层提供接口定义，具体的实现交给外部框架或技术来处理，而领域层只关注业务逻辑，通过接口进行交互。

## 依赖注入与接口抽象

依赖注入是实现领域层与基础设施层解耦的一种常用方法。通过依赖注入，领域层无需关心具体的实现细节，只通过接口与基础设施层交互。常见的依赖注入方法包括构造函数注入、方法注入等。

例如，假设我们有一个订单聚合，它依赖于 `OrderRepository` 来持久化订单数据。在领域层中，我们只定义接口，而不关心具体的实现：

```java
public interface OrderRepository {
    void save(Order order);
    Order findById(Long id);
}
```

在基础设施层中，`OrderRepository` 的实现可能使用 JPA 或 MyBatis 来进行数据库操作：

```java
@Repository
public class JpaOrderRepository implements OrderRepository {
    private final EntityManager entityManager;

    public JpaOrderRepository(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void save(Order order) {
        entityManager.persist(order);
    }

    @Override
    public Order findById(Long id) {
        return entityManager.find(Order.class, id);
    }
}
```

在应用层或服务层，我们通过依赖注入来获取 `OrderRepository` 的实现，避免在领域层直接依赖数据库操作的实现：

```java
@Service
public class OrderService {
    private final OrderRepository orderRepository;

    @Autowired
    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder(Order order) {
        orderRepository.save(order);
    }
}
```

## 领域事件与基础设施的解耦

领域事件是领域模型中用于捕捉和传递业务变化的重要机制。当业务逻辑发生变化时，领域事件能够通知系统其他部分进行处理。为了保持领域层的纯粹性，我们将事件的发布和处理交给基础设施层的实现。

例如，当订单创建时，可能需要触发一个“订单已创建”的领域事件。我们在领域层定义事件：

```java
public class OrderCreatedEvent {
    private final Order order;

    public OrderCreatedEvent(Order order) {
        this.order = order;
    }

    public Order getOrder() {
        return order;
    }
}
```

然后，通过事件发布机制将事件传递给基础设施层进行处理。例如，我们可以使用事件总线来解耦领域层和事件处理的实现：

```java
public interface EventBus {
    void publish(DomainEvent event);
}

@Service
public class SimpleEventBus implements EventBus {
    private final ApplicationEventPublisher publisher;

    public SimpleEventBus(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public void publish(DomainEvent event) {
        publisher.publishEvent(event);
    }
}
```

通过这种方式，领域层仅负责生成事件，而基础设施层负责事件的处理和分发，保持了领域层的独立性。

## 聚合根与持久化的解耦

聚合根负责管理聚合内实体的生命周期，但它并不直接参与持久化操作。持久化操作应该由专门的仓储（Repository）来处理，仓储接口在领域层定义，而具体实现则在基础设施层进行。通过这种方式，领域层不需要了解数据的持久化方式，从而保持领域模型的纯粹性。

```java
public interface OrderRepository {
    void save(Order order);
    Order findById(Long id);
}
```

在领域服务中，我们只关心聚合根的业务逻辑，而不需要关心数据如何存储：

```java
public class OrderService {
    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder(Order order) {
        orderRepository.save(order);
    }
}
```

## 使用防腐层（Anti-Corruption Layer）

防腐层是用于保护领域层免受外部系统或基础设施的影响的一种设计模式。当领域模型需要与外部系统交互时，通过防腐层来隔离外部系统与领域模型的直接依赖，从而保证领域层的独立性和纯粹性。

防腐层通常包含适配器（Adapter）和转换器（Translator），它们负责将外部系统的数据转换为领域模型可理解的格式，避免外部系统的复杂性污染到领域层。

```java
public class ExternalOrderServiceAdapter implements OrderRepository {
    private final ExternalOrderApi externalOrderApi;

    public ExternalOrderServiceAdapter(ExternalOrderApi externalOrderApi) {
        this.externalOrderApi = externalOrderApi;
    }

    @Override
    public void save(Order order) {
        // 将领域模型转换为外部系统格式
        ExternalOrder externalOrder = convertToExternalOrder(order);
        externalOrderApi.saveOrder(externalOrder);
    }

    private ExternalOrder convertToExternalOrder(Order order) {
        // 转换逻辑
        return new ExternalOrder(order.getId(), order.getTotal());
    }
}
```

## 总结

通过基础设施与领域解耦，领域层能够保持独立性，从而实现更高的灵活性和可维护性。依赖注入、接口抽象、领域事件和防腐层等设计模式都是解耦的有效手段。通过这些方法，我们可以确保领域层专注于业务逻辑，而基础设施层则负责与外部系统的交互和具体实现。这种解耦有助于提高代码的可测试性、可扩展性和与业务需求的高度契合。
