# 接口适配层设计

URL: https://caijiao.org/ddd/chapter5/interface-adapter
Source: docs/ddd/chapter5/interface-adapter.md
Description: 介绍如何设计接口适配层，确保领域层与外部系统的通信符合解耦和可扩展的原则。

接口适配层（Interface Adapter Layer）是连接领域层和外部系统（如用户界面、数据库、外部服务等）之间的桥梁。其主要职责是将外部的请求转换为领域层可以理解的格式，或者将领域层的响应转化为外部系统需要的格式。接口适配层帮助我们实现领域驱动设计中的解耦原则，确保领域层保持纯粹，避免与外部框架和技术细节耦合。

## 接口适配层的职责

接口适配层的职责可以概括为以下几点：

- **接收请求并转换为领域层需要的格式**：接收外部系统的输入（如 HTTP 请求、消息队列消息等），并将其转换为领域层可以处理的对象。
- **从领域层获取数据并转换为外部系统需要的格式**：将领域模型的输出转换为外部系统可以理解的格式，例如将领域模型转换为 JSON 格式的响应。
- **协调与外部系统的交互**：接口适配层负责调用外部系统接口，并将外部系统的响应数据传递给领域层，或者将领域层的操作结果传递回外部系统。

## REST API 适配设计

在现代应用中，REST API 是最常用的外部接口通信方式。接口适配层通常会负责将 HTTP 请求与领域服务进行适配。例如，用户通过 HTTP 请求调用一个订单服务，接口适配层将请求转换为领域模型，调用领域服务的相应方法，再将返回的数据格式化为 HTTP 响应。

### 请求适配

例如，当用户发送一个创建订单的请求时，接口适配层将 HTTP 请求转换为领域层可以理解的对象：

```java
@RestController
@RequestMapping("/orders")
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(@RequestBody OrderRequest orderRequest) {
        Order order = new Order(orderRequest.getId(), orderRequest.getTotal());
        orderService.createOrder(order);
        OrderResponse orderResponse = new OrderResponse(order.getId(), order.getTotal());
        return ResponseEntity.status(HttpStatus.CREATED).body(orderResponse);
    }
}
```

在上面的代码中，`OrderController` 作为接口适配层的一部分，接收来自客户端的 `OrderRequest` 对象，并将其转换为领域对象 `Order`。接着，调用领域服务 `orderService.createOrder` 处理业务逻辑，最后将领域对象转换为 API 响应对象 `OrderResponse` 返回给客户端。

### 响应适配

当领域层返回数据时，接口适配层负责将领域模型转换为合适的响应格式。通常，这种转换是通过专门的 DTO（数据传输对象）进行的，以确保响应格式符合外部系统的要求。

```java
public class OrderResponse {
    private Long id;
    private BigDecimal total;

    public OrderResponse(Long id, BigDecimal total) {
        this.id = id;
        this.total = total;
    }

    // Getters and Setters
}
```

在上面的代码中，`OrderResponse` 是适配层用来传递给客户端的响应对象，它不直接暴露领域模型 `Order` 的内部细节，而是提供了一个简化的响应格式。

## DTO 转换

DTO（数据传输对象）用于在层与层之间传递数据，通常用于接口适配层与领域层之间的数据交换。DTO 是为了传输数据而设计的，它不包含业务逻辑，通常与领域模型有所不同。

在设计 DTO 时，我们需要确保它们能够满足外部系统（如前端或其他服务）的需求，而不暴露领域模型的细节。

### 示例

例如，创建订单的 API 可能需要一个 `OrderRequest` DTO，包含必要的字段：

```java
public class OrderRequest {
    private Long id;
    private BigDecimal total;

    // Getters and Setters
}
```

`OrderRequest` DTO 只包含订单创建所需的字段，接口适配层会将它转化为领域模型 `Order`：

```java
public class Order {
    private Long id;
    private BigDecimal total;

    public Order(Long id, BigDecimal total) {
        this.id = id;
        this.total = total;
    }

    // Getters and Setters
}
```

DTO 的转换是接口适配层的关键任务，确保了外部系统与领域层之间的解耦。

## 异常处理与防腐层

在设计接口适配层时，异常处理也是非常重要的。接口适配层应该捕捉领域层抛出的异常，并将其转换为适当的外部响应。例如，当业务逻辑出错时，接口适配层可以将领域层抛出的业务异常转换为 HTTP 错误响应。

```java
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(OrderNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleOrderNotFound(OrderNotFoundException ex) {
        ErrorResponse errorResponse = new ErrorResponse("ORDER_NOT_FOUND", ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
    }
}
```

上面的代码展示了一个全局异常处理器，它会捕捉 `OrderNotFoundException` 异常，并将其转换为 HTTP 404 错误响应。

## 防腐层设计

防腐层（Anti-Corruption Layer，ACL）是一种常用于保护领域层不受外部系统影响的设计模式。接口适配层在某些情况下充当防腐层的角色，当领域层需要与外部系统进行交互时，防腐层确保外部系统的实现细节不会污染领域模型。

防腐层通常包含适配器（Adapter）和转换器（Translator），它们负责将外部系统的数据转换为领域模型可以理解的格式。例如，当领域层需要调用外部的订单管理系统时，防腐层将外部系统的数据格式转换为领域模型的数据格式，从而保证领域层的独立性。

## 总结

接口适配层是实现领域驱动设计中解耦和灵活性的重要组成部分。通过适配外部系统的请求和响应，接口适配层使得领域层能够保持纯粹和专注于业务逻辑。设计良好的接口适配层能够确保领域层与外部系统的无缝对接，同时避免直接依赖外部技术或框架的实现细节。
