学习笔记八

领域驱动设计核心概念
为什么需要DDD?
java
// 传统CRUD开发的痛点
@Service
public class OrderService {

// 贫血模型:只有数据,没有业务逻辑
@Data
public class Order {
private Long id;
private Long userId;
private BigDecimal amount;
private String status;
private List items;
// 只有getter/setter,没有业务方法
}

// 业务逻辑散落在Service中
public void submitOrder(Order order) {
// 1. 校验库存
checkInventory(order);

// 2. 计算金额
calculateAmount(order);

// 3. 检查用户余额
checkUserBalance(order);

// 4. 扣减库存
reduceInventory(order);

// 5. 创建订单
saveOrder(order);

// 6. 发送消息
sendOrderCreatedEvent(order);
}
}

/*
问题:

  1. 业务逻辑无法复用

  2. 领域知识丢失

  3. 需求变更困难

  4. 代码难以理解
    */
    DDD核心概念
    java
    // 1. 实体(Entity):有唯一标识,可变
    @Getter
    public class Order {
    private final OrderId id; // 值对象作为ID
    private OrderStatus status; // 状态枚举
    private Money totalAmount; // 值对象
    private List items;
    private DeliveryAddress deliveryAddress;

    // 实体有业务行为
    public void addItem(Product product, int quantity) {
    // 业务规则:不能添加已取消订单的商品
    if (this.status == OrderStatus.CANCELLED) {
    throw new OrderAlreadyCancelledException();
    }

    OrderItem item = new OrderItem(product, quantity);
    this.items.add(item);
    this.totalAmount = calculateTotalAmount(); // 重新计算总额
    }

    public void submit() {
    // 业务规则:订单必须有商品
    if (items.isEmpty()) {
    throw new EmptyOrderException();
    }

    // 业务规则:金额必须大于0
    if (totalAmount.lessThan(Money.ZERO)) {
    throw new InvalidOrderAmountException();
    }

    this.status = OrderStatus.SUBMITTED;
    registerEvent(new OrderSubmittedEvent(this.id));
    }

    public void cancel() {
    // 业务规则:已支付的订单不能取消
    if (this.status == OrderStatus.PAID) {
    throw new PaidOrderCannotBeCancelledException();
    }

    this.status = OrderStatus.CANCELLED;
    registerEvent(new OrderCancelledEvent(this.id));
    }
    }

// 2. 值对象(Value Object):无标识,不可变
@Value
public class Money {
BigDecimal amount;
Currency currency;

// 业务方法:加法(返回新对象,不修改原对象)
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new CurrencyMismatchException();
}
return new Money(this.amount.add(other.amount), this.currency);
}

// 业务规则验证
public boolean isGreaterThan(Money other) {
return this.amount.compareTo(other.amount) > 0;
}
}

// 3. 聚合(Aggregate):一致性边界
public class Order extends AggregateRoot {

private List items; // 聚合内的实体
private Payment payment; // 聚合内的值对象
private DeliveryInfo deliveryInfo; // 聚合内的值对象

// 聚合内的一致性规则
public void pay(CreditCard card) {
// 规则1:只能支付已提交的订单
if (this.status != OrderStatus.SUBMITTED) {
throw new InvalidOrderStatusException();
}

// 规则2:支付金额必须等于订单总额
Payment payment = new Payment(this.totalAmount, card);
this.payment = payment;
this.status = OrderStatus.PAID;

registerEvent(new OrderPaidEvent(this.id));
}

// 通过ID引用其他聚合
private UserId userId; // 只引用ID,不直接引用User聚合
}

// 4. 领域服务(Domain Service):跨多个聚合的业务逻辑
@Service
@DomainService
public class OrderPlacementService {

private final OrderRepository orderRepository;
private final InventoryService inventoryService;
private final PaymentService paymentService;

public Order placeOrder(Order order, PaymentInfo payment) {
// 跨聚合的业务逻辑
// 1. 检查库存
inventoryService.checkAvailability(order.getItems());

// 2. 创建订单(Order聚合的行为)
order.submit();

// 3. 处理支付(Payment聚合的行为)
payment.process(order.getTotalAmount());

// 4. 保存订单
orderRepository.save(order);

return order;
}
}

// 5. 领域事件(Domain Event):记录重要事件
@Getter
public class OrderSubmittedEvent extends DomainEvent {
private final OrderId orderId;
private final Money totalAmount;
private final LocalDateTime submittedAt;

public OrderSubmittedEvent(OrderId orderId, Money totalAmount) {
this.orderId = orderId;
this.totalAmount = totalAmount;
this.submittedAt = LocalDateTime.now();
}
}

// 事件监听器
@Component
public class OrderEventListener {

@EventListener
public void handleOrderSubmitted(OrderSubmittedEvent event) {
// 1. 发送通知
sendNotification(event);

// 2. 更新统计
updateStatistics(event);

// 3. 触发后续流程
startWorkflow(event);
}
}

posted @ 2026-03-12 22:07  Lomook  阅读(9)  评论(0)    收藏  举报