6Implementing Domain-Driven Design

集成

系统集成

上下文映射模式防腐层开放主机服务发布语言

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第6章:集成(Integration)

一、导读

1.1 本章学习目标

第6章讲解限界上下文之间的集成方式。

本章的核心学习目标包括:

  • 掌握上下文映射的实现模式
  • 理解防腐层的设计
  • 学会使用领域事件进行集成
  • 理解 CQRS 和事件溯源

1.2 为什么本章如此重要

系统不是孤立的——上下文之间需要协作。错误的集成方式会导致上下文之间的耦合,破坏限界边界的隔离。

1.3 核心问题引导

防腐层如何保护内部模型?

领域事件如何实现松耦合集成?

CQRS 解决了什么问题?

事件溯源有什么优缺点?


二、核心概念详解

2.1 防腐层

java
// 防腐层:隔离外部系统的模型
public class ExternalPaymentGateway implements PaymentGateway {
    private StripeClient stripe;    // 外部 SDK
    
    @Override
    public PaymentResult processPayment(PaymentCommand cmd) {
        // 将内部模型转换为外部模型
        StripeChargeRequest request = new StripeChargeRequest();
        request.setAmount(cmd.getAmount().getAmount().intValue());
        request.setCurrency(cmd.getAmount().getCurrency().getCode());
        request.setSource(cmd.getToken());
        
        // 调用外部服务
        StripeChargeResponse response = stripe.charge(request);
        
        // 将外部模型转换回内部模型
        return new PaymentResult(
            response.getId(),
            PaymentStatus.fromStripe(response.getStatus()),
            response.getReceiptUrl()
        );
    }
}

2.2 领域事件集成

java
// 发布事件
public class OrderApplicationService {
    private EventPublisher eventPublisher;
    
    public void confirmOrder(ConfirmOrderCommand cmd) {
        Order order = orderRepository.findById(cmd.getOrderId());
        order.confirm();
        orderRepository.save(order);
        
        // 发布领域事件
        for (DomainEvent event : order.getEvents()) {
            eventPublisher.publish(event);
        }
    }
}

// 消费事件
public class InventoryEventHandler {
    @EventListener
    public void onOrderConfirmed(OrderConfirmed event) {
        // 更新库存
        for (OrderLineItem item : event.getItems()) {
            inventoryService.reduceStock(item.getProductId(), item.getQuantity());
        }
    }
}

2.3 CQRS

java
// 命令端:修改状态
public class OrderCommandHandler {
    public void placeOrder(PlaceOrderCommand cmd) {
        Order order = new Order(cmd.getCustomerId());
        // ... 业务逻辑
        orderRepository.save(order);
        eventPublisher.publish(new OrderPlaced(order.getId()));
    }
}

// 查询端:读取数据(使用专门的读模型)
public class OrderQueryService {
    private JdbcTemplate jdbc;    // 直接用 SQL 查询
    
    public List<OrderView> findOrders(OrderQuery query) {
        String sql = "SELECT o.id, o.total, c.name FROM orders o " +
                     "JOIN customers c ON o.customer_id = c.id " +
                     "WHERE o.status = ?";
        return jdbc.query(sql, new Object[]{query.getStatus()}, 
            (rs, n) -> new OrderView(rs.getString("id"), rs.getBigDecimal("total")));
    }
}

三、实战案例

3.1 案例一:事件溯源

java
// 事件溯源:用事件序列表示状态
public class Order {
    private OrderId id;
    private List<OrderLine> lines = new ArrayList<>();
    private OrderStatus status = OrderStatus.DRAFT;
    private List<DomainEvent> changes = new ArrayList<>();
    
    // 应用事件
    public void apply(DomainEvent event) {
        if (event instanceof OrderLineAdded) {
            OrderLineAdded e = (OrderLineAdded) event;
            lines.add(new OrderLine(e.getProductId(), e.getQuantity()));
        } else if (event instanceof OrderConfirmed) {
            status = OrderStatus.CONFIRMED;
        }
        changes.add(event);
    }
    
    // 执行业务操作
    public void addLine(ProductId productId, int quantity) {
        apply(new OrderLineAdded(id, productId, quantity));
    }
    
    // 从事件重建状态
    public static Order rehydrate(OrderId id, List<DomainEvent> events) {
        Order order = new Order();
        order.id = id;
        events.forEach(order::apply);
        return order;
    }
}

四、本章小结

防腐层:隔离外部系统模型。

领域事件:松耦合的上下文集成。

CQRS:命令和查询分离,优化读写性能。

事件溯源:用事件序列表示状态。


五、思考与练习

设计一个防腐层来隔离第三方支付网关。

用领域事件实现订单和库存上下文的集成。

CQRS 在什么场景下最有价值?


6/7集成
0%