# DDD 实现

作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)


# DDD架构:单体应用实现

在单体应用中,虽然所有的业务逻辑、数据和服务都运行在同一个进程和数据库中,但依然可以遵循 DDD 的设计原则,利用 领域模型 来组织代码,并通过 模块化 来划分业务领域。

# 核心领域模型

在单体应用中,DDD 的核心概念(如实体、值对象、聚合根、领域服务等)依然适用。你可以将系统的不同业务领域抽象为独立的 领域模型,并确保每个模块专注于自己的业务功能。

举个例子,假设我们在构建一个电商系统,其中涉及订单、支付、库存和物流等多个业务领域。

// 订单领域模型(Order Domain)
public class Order {
    private String id;
    private String customerId;
    private List<OrderItem> items;
    private OrderStatus status;

    public void addItem(OrderItem item) {
        // 业务逻辑:添加商品到订单
    }

    public void changeStatus(OrderStatus newStatus) {
        // 业务逻辑:修改订单状态
        this.status = newStatus;
    }

    // 其他领域方法
}

public class OrderItem {
    private String productId;
    private int quantity;

    // 其他领域方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 模块化设计

在单体应用中,你可以通过 模块 来划分领域。每个模块对应系统中的一个领域,模块内部可以有实体、聚合根、值对象、领域服务等,而模块之间通过接口和领域事件进行交互。

  • 订单模块(Order Module):包含订单相关的所有实体、聚合根和领域服务。
  • 支付模块(Payment Module):处理支付相关的业务逻辑。
  • 库存模块(Inventory Module):管理商品库存。
  • 物流模块(Logistics Module):处理物流配送。

模块划分有助于代码的清晰性和可维护性。在 Spring 框架中,模块可以通过包结构、接口层、服务层等方式实现。

// 订单服务(Order Service)
@Service
public class OrderService {
    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder(Order order) {
        orderRepository.save(order);  // 订单保存到数据库
    }

    public void updateOrderStatus(String orderId, OrderStatus status) {
        Order order = orderRepository.findById(orderId);
        order.changeStatus(status);
        orderRepository.save(order);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 领域事件与防腐层

即使在单体应用中,领域事件和防腐层的概念也非常重要。如果不同模块之间需要通过事件进行通信,或者某个模块需要调用外部系统,我们依然可以使用领域事件和防腐层。

例如,库存模块可能需要在订单成功支付后减少库存,这时可以通过领域事件来解耦订单服务与库存服务。

// 订单支付成功后发布领域事件
public class OrderPaidEvent {
    private String orderId;
    private String customerId;

    // 构造函数、getter、setter等
}

@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;

    public OrderService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void payOrder(String orderId) {
        // 支付成功,发布领域事件
        eventPublisher.publishEvent(new OrderPaidEvent(orderId, "customer123"));
    }
}

// 库存服务监听订单支付成功事件
@Service
public class InventoryService {
    @EventListener
    public void handleOrderPaidEvent(OrderPaidEvent event) {
        // 处理库存减少的业务逻辑
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 单体应用中的防腐层

如果你的单体应用需要与外部系统集成,防腐层依然可以用来隔离外部服务的实现细节,确保你内部的领域模型不受外部服务影响。

public class ExternalPaymentService {
    public PaymentResponse makePayment(PaymentRequest request) {
        // 调用外部支付服务
        return new PaymentResponse();
    }
}

public class PaymentFacade {
    private final ExternalPaymentService externalPaymentService;

    public PaymentFacade(ExternalPaymentService externalPaymentService) {
        this.externalPaymentService = externalPaymentService;
    }

    public PaymentResponse processPayment(PaymentRequest request) {
        // 防腐层:转换请求数据并调用外部支付服务
        return externalPaymentService.makePayment(request);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# DDD架构:微服务实现

在微服务架构中,DDD 的设计理念依然适用,只不过由于微服务本身是 分布式 的,我们需要更加关注服务间的通信、数据一致性和领域解耦等问题。

# 微服务中的领域(服务)

在微服务架构中,每个 领域 对应一个独立的 微服务。每个微服务聚焦于自己的业务领域,拥有自己的数据存储、API 和业务逻辑。微服务之间通常通过 REST、GraphQL、gRPC 或消息队列等方式进行通信。

例如,订单、支付、库存等每个模块都可以是一个独立的微服务:

  • 订单微服务(Order Service):处理与订单相关的所有操作。
  • 支付微服务(Payment Service):专注于支付逻辑。
  • 库存微服务(Inventory Service):负责库存管理。

每个微服务都根据 DDD 的设计原则,围绕各自的领域来构建。

# 微服务间的通信与防腐层

在微服务架构中,防腐层尤为重要。因为服务间的通信往往会涉及到数据的转换、协议的适配以及接口的规范等,防腐层可以帮助微服务之间保持独立性。

// 库存微服务通过 REST API 与订单微服务通信
public class InventoryService {
    private final RestTemplate restTemplate;

    public InventoryService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public InventoryResponse checkInventory(String productId) {
        // 防腐层:调用外部订单微服务
        return restTemplate.getForObject("http://order-service/checkInventory/" + productId, InventoryResponse.class);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 跨微服务的领域事件

在微服务架构中,领域事件 是解耦微服务之间的重要手段。当一个微服务的领域模型发生变化时,它会发布领域事件,其他微服务可以订阅这些事件并做出响应。通过这种方式,微服务之间可以在不直接依赖的情况下协同工作。

举个例子,订单微服务 在订单支付成功后发布 OrderPaidEvent库存微服务 订阅这个事件并更新库存。

// 订单微服务发布领域事件
public class OrderPaidEvent {
    private String orderId;

    // 构造函数、getter、setter等
}

// 库存微服务订阅领域事件
public class InventoryService {
    @EventListener
    public void handleOrderPaidEvent(OrderPaidEvent event) {
        // 更新库存
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 业务聚合层(BP层)

在微服务架构中,业务聚合层(BP层)常常作为 API 网关业务协调层,它负责从多个微服务中获取数据并进行聚合,然后返回给前端。BP层避免了前端直接调用多个微服务的多个 API,提升了性能和用户体验。

public class OrderBPService {
    private final OrderService orderService;
    private final PaymentService paymentService;
    private final InventoryService inventoryService;

    public OrderBPService(OrderService orderService, PaymentService paymentService, InventoryService inventoryService) {
        this.orderService = orderService;
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }

    public OrderDetailsDTO getOrderDetails(String orderId) {
        // 调用多个微服务并聚合数据
        Order order = orderService.getOrder(orderId);
        PaymentStatus paymentStatus = paymentService.getPaymentStatus(orderId);
        InventoryStatus inventoryStatus = inventoryService.getInventoryStatus(order.getProductId());

        return new OrderDetailsDTO(order, paymentStatus, inventoryStatus);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 微服务中的防腐层

在微服务架构中,防腐层通常表现为 服务间的适配层,它可以负责处理不同微服务之间的通信协议、数据格式的转换等。

public class OrderServiceFacade {
    private final InventoryService inventoryService;

    public OrderServiceFacade(InventoryService inventoryService) {
        this.inventoryService = inventoryService;
    }

    public
1
2
3
4
5
6
7
8