当前位置: 首页 > news >正文

B.10.01.6-DDD领域驱动设计:从理论到落地的完整指南


title: “DDD领域驱动设计:从理论到落地的完整指南”
subtitle: “构建复杂业务系统的架构思维与实践方法”
date: “2024-12-09”
category: “代码内功修炼”
tags: [“DDD”, “领域驱动设计”, “架构设计”, “业务建模”]
description: “深入解析DDD核心概念,提供从业务分析到代码实现的完整实践指南”

🎯 业务场景:电商平台的复杂业务挑战

背景挑战

假如你正在负责一个大型电商平台的架构设计,面临以下典型问题:

业务复杂性爆炸

  • 订单管理:普通订单、预售订单、团购订单、秒杀订单等多种类型
  • 库存管理:实物库存、虚拟库存、预占库存、安全库存等复杂逻辑
  • 价格计算:会员价、促销价、阶梯价、区域价等多维度定价
  • 支付流程:支付、退款、分期、代付等多种支付场景

技术债务累积

  • 代码耦合严重:订单、库存、支付逻辑混杂在一起
  • 数据模型混乱:同一个概念在不同模块有不同的表示
  • 业务规则分散:相同的业务逻辑在多处重复实现
  • 扩展困难:新增业务类型需要修改大量现有代码

量化指标

  • 支持 20+ 种不同的订单类型
  • 管理 100万+ SKU商品库存
  • 处理 日均50万 笔订单

🔍 技术分析:DDD核心概念与传统开发对比

DDD vs 传统开发模式

对比维度传统开发模式DDD领域驱动设计
设计起点数据库表结构业务领域模型
代码组织按技术分层(Controller、Service、DAO)按业务领域分模块
业务逻辑分散在Service层封装在领域对象中
数据模型贫血模型(只有getter/setter)充血模型(包含业务行为)
团队协作技术人员主导业务专家与技术人员协作
变更响应牵一发动全身领域内变更影响范围可控

DDD分层架构

基础设施层
领域层
应用层
用户接口层
数据库
消息队列
外部服务
缓存
聚合根
实体
值对象
领域服务
领域事件
应用服务
命令处理器
查询处理器
REST API
Web页面
消息队列
用户接口层 User Interface
应用层 Application
领域层 Domain
基础设施层 Infrastructure

核心概念解析

1. 限界上下文 (Bounded Context)

定义:明确的业务边界,在这个边界内,特定的领域模型是一致和有效的。

电商平台的限界上下文划分

  • 商品目录上下文:商品信息管理、分类、搜索
  • 订单管理上下文:订单创建、状态流转、订单履行
  • 库存管理上下文:库存扣减、补货、盘点
  • 支付上下文:支付处理、退款、对账
  • 用户上下文:用户注册、认证、权限管理

2. 聚合 (Aggregate)

定义:一组相关对象的集合,作为数据修改的单元,确保业务不变性。

设计原则

  • 一个聚合只有一个聚合根
  • 聚合内部保证强一致性
  • 聚合之间通过ID引用,保证最终一致性
  • 聚合应该尽可能小

3. 领域事件 (Domain Event)

定义:领域中发生的重要业务事件,用于解耦不同聚合之间的交互。


🏗️ 架构设计:订单聚合的DDD实现

1. 订单聚合设计

聚合根:Order

@Entity
@Table(name = "orders")
public class Order {@EmbeddedIdprivate OrderId orderId;@Embeddedprivate CustomerId customerId;@ElementCollection@CollectionTable(name = "order_items")private List<OrderItem> orderItems;@Embeddedprivate ShippingAddress shippingAddress;@Enumerated(EnumType.STRING)private OrderStatus status;@Embeddedprivate Money totalAmount;private LocalDateTime createdAt;private LocalDateTime updatedAt;// 领域事件@Transientprivate List<DomainEvent> domainEvents = new ArrayList<>();// 私有构造函数,强制通过工厂方法创建protected Order() {}// 工厂方法:创建订单public static Order create(CustomerId customerId, List<OrderItem> items, ShippingAddress shippingAddress) {// 业务规则验证validateOrderCreation(customerId, items, shippingAddress);Order order = new Order();order.orderId = OrderId.generate();order.customerId = customerId;order.orderItems = new ArrayList<>(items);order.shippingAddress = shippingAddress;order.status = OrderStatus.PENDING;order.totalAmount = calculateTotalAmount(items);order.createdAt = LocalDateTime.now();order.updatedAt = LocalDateTime.now();// 发布领域事件order.addDomainEvent(new OrderCreatedEvent(order.orderId, order.customerId));return order;}// 业务行为:确认订单public void confirm() {// 业务规则:只有待处理的订单才能确认if (this.status != OrderStatus.PENDING) {throw new IllegalOrderStateException(String.format("订单状态为%s,无法确认", this.status));}this.status = OrderStatus.CONFIRMED;this.updatedAt = LocalDateTime.now();// 发布领域事件addDomainEvent(new OrderConfirmedEvent(this.orderId, this.customerId));}// 业务行为:取消订单public void cancel(String reason) {// 业务规则:已发货的订单不能取消if (this.status == OrderStatus.SHIPPED || this.status == OrderStatus.DELIVERED) {throw new IllegalOrderStateException("订单已发货,无法取消");}if (this.status == OrderStatus.CANCELLED) {return; // 幂等性处理}this.status = OrderStatus.CANCELLED;this.updatedAt = LocalDateTime.now();// 发布领域事件addDomainEvent(new OrderCancelledEvent(this.orderId, this.customerId, reason));}// 业务行为:添加订单项public void addOrderItem(OrderItem item) {// 业务规则:只有待处理的订单才能添加商品if (this.status != OrderStatus.PENDING) {throw new IllegalOrderStateException("订单已确认,无法添加商品");}// 检查是否已存在相同商品Optional<OrderItem> existingItem = orderItems.stream().filter(oi -> oi.getProductId().equals(item.getProductId())).findFirst();if (existingItem.isPresent()) {// 合并数量existingItem.get().increaseQuantity(item.getQuantity());} else {// 添加新商品this.orderItems.add(item);}// 重新计算总金额this.totalAmount = calculateTotalAmount(this.orderItems);this.updatedAt = LocalDateTime.now();}// 业务查询:是否可以取消public boolean canBeCancelled() {return this.status == OrderStatus.PENDING || this.status == OrderStatus.CONFIRMED;}// 业务查询:获取订单摘要public OrderSummary getSummary() {return OrderSummary.builder().orderId(this.orderId.getValue()).customerName(getCustomerName()) // 通过领域服务获取.itemCount(this.orderItems.size()).totalAmount(this.totalAmount.getAmount()).status(this.status.getDisplayName()).createdAt(this.createdAt).build();}// 私有方法:验证订单创建private static void validateOrderCreation(CustomerId customerId, List<OrderItem> items, ShippingAddress shippingAddress) {if (customerId == null) {throw new IllegalArgumentException("客户ID不能为空");}if (items == null || items.isEmpty()) {throw new IllegalArgumentException("订单商品不能为空");}if (shippingAddress == null) {throw new IllegalArgumentException("收货地址不能为空");}// 验证商品数量for (OrderItem item : items) {if (item.getQuantity() <= 0) {throw new IllegalArgumentException("商品数量必须大于0");}}}// 私有方法:计算总金额private static Money calculateTotalAmount(List<OrderItem> items) {BigDecimal total = items.stream().map(item -> item.getSubtotal().getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);return new Money(total);}// 领域事件管理public void addDomainEvent(DomainEvent event) {this.domainEvents.add(event);}public List<DomainEvent> getDomainEvents() {return Collections.unmodifiableList(domainEvents);}public void clearDomainEvents() {this.domainEvents.clear();}// Getterspublic OrderId getOrderId() { return orderId; }public CustomerId getCustomerId() { return customerId; }public List<OrderItem> getOrderItems() { return Collections.unmodifiableList(orderItems); }public OrderStatus getStatus() { return status; }public Money getTotalAmount() { return totalAmount; }public LocalDateTime getCreatedAt() { return createdAt; }
}

值对象:OrderId

@Embeddable
public class OrderId {@Column(name = "order_id")private String value;// JPA需要的默认构造函数protected OrderId() {}private OrderId(String value) {if (StringUtils.isBlank(value)) {throw new IllegalArgumentException("订单ID不能为空");}this.value = value;}public static OrderId of(String value) {return new OrderId(value);}public static OrderId generate() {String id = "ORD" + System.currentTimeMillis() + String.format("%04d", new Random().nextInt(10000));return new OrderId(id);}public String getValue() {return value;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;OrderId orderId = (OrderId) o;return Objects.equals(value, orderId.value);}@Overridepublic int hashCode() {return Objects.hash(value);}@Overridepublic String toString() {return value;}
}

值对象:Money

@Embeddable
public class Money {@Column(name = "amount", precision = 19, scale = 2)private BigDecimal amount;@Column(name = "currency")private String currency;protected Money() {}public Money(BigDecimal amount) {this(amount, "CNY");}public Money(BigDecimal amount, String currency) {if (amount == null) {throw new IllegalArgumentException("金额不能为空");}if (amount.compareTo(BigDecimal.ZERO) < 0) {throw new IllegalArgumentException("金额不能为负数");}if (StringUtils.isBlank(currency)) {throw new IllegalArgumentException("货币类型不能为空");}this.amount = amount.setScale(2, RoundingMode.HALF_UP);this.currency = currency;}public Money add(Money other) {if (!this.currency.equals(other.currency)) {throw new IllegalArgumentException("不同货币类型无法相加");}return new Money(this.amount.add(other.amount), this.currency);}public Money subtract(Money other) {if (!this.currency.equals(other.currency)) {throw new IllegalArgumentException("不同货币类型无法相减");}BigDecimal result = this.amount.subtract(other.amount);if (result.compareTo(BigDecimal.ZERO) < 0) {throw new IllegalArgumentException("计算结果不能为负数");}return new Money(result, this.currency);}public Money multiply(int multiplier) {return new Money(this.amount.multiply(BigDecimal.valueOf(multiplier)), this.currency);}public boolean isGreaterThan(Money other) {if (!this.currency.equals(other.currency)) {throw new IllegalArgumentException("不同货币类型无法比较");}return this.amount.compareTo(other.amount) > 0;}public boolean isZero() {return this.amount.compareTo(BigDecimal.ZERO) == 0;}// Getterspublic BigDecimal getAmount() { return amount; }public String getCurrency() { return currency; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Money money = (Money) o;return Objects.equals(amount, money.amount) && Objects.equals(currency, money.currency);}@Overridepublic int hashCode() {return Objects.hash(amount, currency);}@Overridepublic String toString() {return String.format("%s %s", amount, currency);}
}

2. 领域服务实现

订单定价服务

@Component
public class OrderPricingService {private final PricingRuleRepository pricingRuleRepository;private final CustomerRepository customerRepository;public OrderPricingService(PricingRuleRepository pricingRuleRepository,CustomerRepository customerRepository) {this.pricingRuleRepository = pricingRuleRepository;this.customerRepository = customerRepository;}/*** 计算订单价格*/public OrderPricing calculatePricing(Order order) {Customer customer = customerRepository.findById(order.getCustomerId()).orElseThrow(() -> new CustomerNotFoundException(order.getCustomerId()));// 获取适用的定价规则List<PricingRule> applicableRules = pricingRuleRepository.findApplicableRules(customer.getMemberLevel(), order.getTotalAmount());Money originalAmount = order.getTotalAmount();Money discountAmount = Money.ZERO;List<AppliedDiscount> appliedDiscounts = new ArrayList<>();// 应用定价规则for (PricingRule rule : applicableRules) {if (rule.isApplicable(order, customer)) {Money ruleDiscount = rule.calculateDiscount(order, customer);discountAmount = discountAmount.add(ruleDiscount);appliedDiscounts.add(new AppliedDiscount(rule.getRuleName(),rule.getDescription(),ruleDiscount));}}Money finalAmount = originalAmount.subtract(discountAmount);return OrderPricing.builder().originalAmount(originalAmount).discountAmount(discountAmount).finalAmount(finalAmount).appliedDiscounts(appliedDiscounts).build();}
}

3. 应用服务实现

订单应用服务

@Service
@Transactional
public class OrderApplicationService {private final OrderRepository orderRepository;private final CustomerRepository customerRepository;private final ProductRepository productRepository;private final OrderPricingService orderPricingService;private final DomainEventPublisher eventPublisher;public OrderApplicationService(OrderRepository orderRepository,CustomerRepository customerRepository,ProductRepository productRepository,OrderPricingService orderPricingService,DomainEventPublisher eventPublisher) {this.orderRepository = orderRepository;this.customerRepository = customerRepository;this.productRepository = productRepository;this.orderPricingService = orderPricingService;this.eventPublisher = eventPublisher;}/*** 创建订单*/public CreateOrderResult createOrder(CreateOrderCommand command) {// 1. 验证客户存在Customer customer = customerRepository.findById(command.getCustomerId()).orElseThrow(() -> new CustomerNotFoundException(command.getCustomerId()));// 2. 验证商品存在并构建订单项List<OrderItem> orderItems = buildOrderItems(command.getOrderItems());// 3. 创建订单聚合Order order = Order.create(command.getCustomerId(),orderItems,command.getShippingAddress());// 4. 计算价格OrderPricing pricing = orderPricingService.calculatePricing(order);order.applyPricing(pricing);// 5. 保存订单orderRepository.save(order);// 6. 发布领域事件publishDomainEvents(order);return CreateOrderResult.builder().orderId(order.getOrderId().getValue()).totalAmount(order.getTotalAmount().getAmount()).status(order.getStatus().name()).build();}/*** 确认订单*/public void confirmOrder(ConfirmOrderCommand command) {Order order = orderRepository.findById(command.getOrderId()).orElseThrow(() -> new OrderNotFoundException(command.getOrderId()));// 执行业务逻辑order.confirm();// 保存变更orderRepository.save(order);// 发布领域事件publishDomainEvents(order);}/*** 取消订单*/public void cancelOrder(CancelOrderCommand command) {Order order = orderRepository.findById(command.getOrderId()).orElseThrow(() -> new OrderNotFoundException(command.getOrderId()));// 执行业务逻辑order.cancel(command.getReason());// 保存变更orderRepository.save(order);// 发布领域事件publishDomainEvents(order);}/*** 查询订单详情*/@Transactional(readOnly = true)public OrderDetailResult getOrderDetail(String orderId) {Order order = orderRepository.findById(OrderId.of(orderId)).orElseThrow(() -> new OrderNotFoundException(OrderId.of(orderId)));return OrderDetailResult.from(order);}// 私有方法:构建订单项private List<OrderItem> buildOrderItems(List<CreateOrderItemCommand> itemCommands) {List<OrderItem> orderItems = new ArrayList<>();for (CreateOrderItemCommand itemCommand : itemCommands) {Product product = productRepository.findById(itemCommand.getProductId()).orElseThrow(() -> new ProductNotFoundException(itemCommand.getProductId()));// 检查库存if (!product.hasEnoughStock(itemCommand.getQuantity())) {throw new InsufficientStockException(itemCommand.getProductId());}OrderItem orderItem = OrderItem.create(itemCommand.getProductId(),product.getName(),product.getPrice(),itemCommand.getQuantity());orderItems.add(orderItem);}return orderItems;}// 私有方法:发布领域事件private void publishDomainEvents(Order order) {List<DomainEvent> events = order.getDomainEvents();for (DomainEvent event : events) {eventPublisher.publish(event);}order.clearDomainEvents();}
}

🛠️ 代码实现:完整的DDD项目结构

项目结构组织

src/main/java/com/ecommerce/
├── order/                          # 订单限界上下文
│   ├── domain/                     # 领域层
│   │   ├── model/                  # 领域模型
│   │   │   ├── Order.java          # 聚合根
│   │   │   ├── OrderItem.java      # 实体
│   │   │   ├── OrderId.java        # 值对象
│   │   │   ├── Money.java          # 值对象
│   │   │   └── OrderStatus.java    # 枚举
│   │   ├── service/                # 领域服务
│   │   │   └── OrderPricingService.java
│   │   ├── repository/             # 仓储接口
│   │   │   └── OrderRepository.java
│   │   └── event/                  # 领域事件
│   │       ├── OrderCreatedEvent.java
│   │       ├── OrderConfirmedEvent.java
│   │       └── OrderCancelledEvent.java
│   ├── application/                # 应用层
│   │   ├── service/                # 应用服务
│   │   │   └── OrderApplicationService.java
│   │   ├── command/                # 命令对象
│   │   │   ├── CreateOrderCommand.java
│   │   │   ├── ConfirmOrderCommand.java
│   │   │   └── CancelOrderCommand.java
│   │   └── result/                 # 结果对象
│   │       ├── CreateOrderResult.java
│   │       └── OrderDetailResult.java
│   ├── infrastructure/             # 基础设施层
│   │   ├── repository/             # 仓储实现
│   │   │   └── JpaOrderRepository.java
│   │   └── event/                  # 事件发布实现
│   │       └── SpringDomainEventPublisher.java
│   └── interfaces/                 # 用户接口层
│       ├── rest/                   # REST API
│       │   └── OrderController.java
│       └── dto/                    # 数据传输对象
│           ├── CreateOrderRequest.java
│           └── OrderResponse.java
├── inventory/                      # 库存限界上下文
├── payment/                        # 支付限界上下文
└── shared/                         # 共享内核├── domain/│   ├── DomainEvent.java│   └── DomainEventPublisher.java└── infrastructure/└── config/

仓储模式实现

仓储接口

public interface OrderRepository {/*** 保存订单*/void save(Order order);/*** 根据ID查找订单*/Optional<Order> findById(OrderId orderId);/*** 根据客户ID查找订单列表*/List<Order> findByCustomerId(CustomerId customerId);/*** 根据状态查找订单*/List<Order> findByStatus(OrderStatus status);/*** 分页查询订单*/Page<Order> findAll(Pageable pageable);/*** 删除订单*/void delete(Order order);/*** 检查订单是否存在*/boolean existsById(OrderId orderId);
}

JPA仓储实现

@Repository
public class JpaOrderRepository implements OrderRepository {private final SpringDataOrderRepository springDataRepository;public JpaOrderRepository(SpringDataOrderRepository springDataRepository) {this.springDataRepository = springDataRepository;}@Overridepublic void save(Order order) {springDataRepository.save(order);}@Overridepublic Optional<Order> findById(OrderId orderId) {return springDataRepository.findById(orderId.getValue());}@Overridepublic List<Order> findByCustomerId(CustomerId customerId) {return springDataRepository.findByCustomerId(customerId.getValue());}@Overridepublic List<Order> findByStatus(OrderStatus status) {return springDataRepository.findByStatus(status);}@Overridepublic Page<Order> findAll(Pageable pageable) {return springDataRepository.findAll(pageable);}@Overridepublic void delete(Order order) {springDataRepository.delete(order);}@Overridepublic boolean existsById(OrderId orderId) {return springDataRepository.existsById(orderId.getValue());}
}// Spring Data JPA接口
interface SpringDataOrderRepository extends JpaRepository<Order, String> {List<Order> findByCustomerId(String customerId);List<Order> findByStatus(OrderStatus status);@Query("SELECT o FROM Order o WHERE o.createdAt BETWEEN :startDate AND :endDate")List<Order> findByCreatedAtBetween(@Param("startDate") LocalDateTime startDate,@Param("endDate") LocalDateTime endDate);
}

领域事件处理

事件发布器

@Component
public class SpringDomainEventPublisher implements DomainEventPublisher {private final ApplicationEventPublisher applicationEventPublisher;public SpringDomainEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}@Overridepublic void publish(DomainEvent event) {applicationEventPublisher.publishEvent(event);}
}

事件处理器

@Component
@Slf4j
public class OrderEventHandler {private final InventoryService inventoryService;private final NotificationService notificationService;private final EmailService emailService;public OrderEventHandler(InventoryService inventoryService,NotificationService notificationService,EmailService emailService) {this.inventoryService = inventoryService;this.notificationService = notificationService;this.emailService = emailService;}/*** 处理订单创建事件*/@EventListener@Asyncpublic void handleOrderCreated(OrderCreatedEvent event) {log.info("处理订单创建事件:{}", event.getOrderId());try {// 预占库存inventoryService.reserveInventory(event.getOrderId(), event.getOrderItems());// 发送订单确认邮件emailService.sendOrderConfirmationEmail(event.getCustomerId(), event.getOrderId());log.info("订单创建事件处理完成:{}", event.getOrderId());} catch (Exception e) {log.error("处理订单创建事件失败:{}", event.getOrderId(), e);// 这里可以实现补偿机制或重试逻辑}}/*** 处理订单确认事件*/@EventListener@Asyncpublic void handleOrderConfirmed(OrderConfirmedEvent event) {log.info("处理订单确认事件:{}", event.getOrderId());try {// 扣减库存inventoryService.deductInventory(event.getOrderId());// 发送确认通知notificationService.sendOrderConfirmedNotification(event.getCustomerId(), event.getOrderId());log.info("订单确认事件处理完成:{}", event.getOrderId());} catch (Exception e) {log.error("处理订单确认事件失败:{}", event.getOrderId(), e);}}/*** 处理订单取消事件*/@EventListener@Asyncpublic void handleOrderCancelled(OrderCancelledEvent event) {log.info("处理订单取消事件:{}", event.getOrderId());try {// 释放库存inventoryService.releaseInventory(event.getOrderId());// 发送取消通知notificationService.sendOrderCancelledNotification(event.getCustomerId(), event.getOrderId(), event.getReason());log.info("订单取消事件处理完成:{}", event.getOrderId());} catch (Exception e) {log.error("处理订单取消事件失败:{}", event.getOrderId(), e);}}
}

REST API实现

订单控制器

@RestController
@RequestMapping("/api/orders")
@Validated
public class OrderController {private final OrderApplicationService orderApplicationService;public OrderController(OrderApplicationService orderApplicationService) {this.orderApplicationService = orderApplicationService;}/*** 创建订单*/@PostMappingpublic ResponseEntity<ApiResponse<CreateOrderResponse>> createOrder(@Valid @RequestBody CreateOrderRequest request) {CreateOrderCommand command = CreateOrderCommand.builder().customerId(CustomerId.of(request.getCustomerId())).orderItems(convertToOrderItems(request.getItems())).shippingAddress(convertToShippingAddress(request.getShippingAddress())).build();CreateOrderResult result = orderApplicationService.createOrder(command);CreateOrderResponse response = CreateOrderResponse.builder().orderId(result.getOrderId()).totalAmount(result.getTotalAmount()).status(result.getStatus()).build();return ResponseEntity.ok(ApiResponse.success(response));}/*** 确认订单*/@PostMapping("/{orderId}/confirm")public ResponseEntity<ApiResponse<Void>> confirmOrder(@PathVariable String orderId) {ConfirmOrderCommand command = ConfirmOrderCommand.builder().orderId(OrderId.of(orderId)).build();orderApplicationService.confirmOrder(command);return ResponseEntity.ok(ApiResponse.success());}/*** 取消订单*/@PostMapping("/{orderId}/cancel")public ResponseEntity<ApiResponse<Void>> cancelOrder(@PathVariable String orderId,@Valid @RequestBody CancelOrderRequest request) {CancelOrderCommand command = CancelOrderCommand.builder().orderId(OrderId.of(orderId)).reason(request.getReason()).build();orderApplicationService.cancelOrder(command);return ResponseEntity.ok(ApiResponse.success());}/*** 查询订单详情*/@GetMapping("/{orderId}")public ResponseEntity<ApiResponse<OrderDetailResponse>> getOrderDetail(@PathVariable String orderId) {OrderDetailResult result = orderApplicationService.getOrderDetail(orderId);OrderDetailResponse response = OrderDetailResponse.from(result);return ResponseEntity.ok(ApiResponse.success(response));}// 私有转换方法private List<CreateOrderItemCommand> convertToOrderItems(List<CreateOrderItemRequest> items) {return items.stream().map(item -> CreateOrderItemCommand.builder().productId(ProductId.of(item.getProductId())).quantity(item.getQuantity()).build()).collect(Collectors.toList());}private ShippingAddress convertToShippingAddress(ShippingAddressRequest request) {return ShippingAddress.builder().receiverName(request.getReceiverName()).phone(request.getPhone()).province(request.getProvince()).city(request.getCity()).district(request.getDistrict()).detailAddress(request.getDetailAddress()).build();}
}

💡 经验总结:DDD落地最佳实践

业务复杂度管理效果

重构后
重构前
领域模型
统一语言
聚合设计
单元测试
持续交付
直接写代码
需求分析混乱
逻辑分散
测试困难
上线风险高
业务需求
领域建模
代码实现
测试验证
部署上线

踩坑经验总结

坑1:过度建模

问题描述:为了追求完美的领域模型,过度抽象和建模

// ❌ 错误示例:过度抽象的订单状态
public abstract class OrderState {public abstract void confirm(Order order);public abstract void cancel(Order order);public abstract void ship(Order order);// ... 20多个状态转换方法
}public class PendingOrderState extends OrderState {// 实现所有方法,大部分抛异常
}// ✅ 正确做法:简单的枚举 + 业务规则
public enum OrderStatus {PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED;public boolean canTransitionTo(OrderStatus target) {return VALID_TRANSITIONS.get(this).contains(target);}
}

解决方案

  • 从简单开始,逐步演进
  • 只对真正复杂的业务逻辑建模
  • 保持模型的简洁性和实用性

坑2:聚合边界划分不当

问题描述:聚合设计过大或过小,影响性能和一致性

// ❌ 错误示例:聚合过大
public class Order {private List<OrderItem> items;private Customer customer;        // 不应该包含完整客户信息private List<Payment> payments;   // 支付应该是独立聚合private Inventory inventory;      // 库存应该是独立聚合// ... 包含了太多不相关的概念
}// ✅ 正确做法:合理的聚合边界
public class Order {private OrderId orderId;private CustomerId customerId;    // 只保存ID引用private List<OrderItem> items;private OrderStatus status;private Money totalAmount;// 只包含订单核心概念
}

解决方案

  • 聚合应该围绕业务不变性设计
  • 聚合间通过ID引用,避免直接对象引用
  • 一个事务只修改一个聚合
  • 聚合大小要适中,通常不超过几个实体

坑3:忽略性能考虑

问题描述:过度追求领域模型纯粹性,忽略性能优化

// ❌ 错误示例:每次都重新计算
public class Order {public Money getTotalAmount() {return orderItems.stream().map(OrderItem::getSubtotal).reduce(Money.ZERO, Money::add);  // 每次调用都重新计算}
}// ✅ 正确做法:缓存计算结果
public class Order {private Money totalAmount;  // 缓存计算结果public void addOrderItem(OrderItem item) {this.orderItems.add(item);this.totalAmount = calculateTotalAmount();  // 状态变更时重新计算}public Money getTotalAmount() {return totalAmount;  // 直接返回缓存值}
}

最佳实践指南

1. 领域建模流程

业务调研
事件风暴
识别聚合
定义限界上下文
设计领域模型
编码实现
测试验证
持续重构

具体步骤

  1. 业务调研:深入了解业务流程和规则
  2. 事件风暴:识别领域事件和业务流程
  3. 识别聚合:找出数据一致性边界
  4. 定义限界上下文:划分业务边界
  5. 设计领域模型:创建实体、值对象、聚合
  6. 编码实现:将模型转换为代码
  7. 测试验证:确保业务逻辑正确
  8. 持续重构:根据业务变化调整模型

2. 代码组织原则

按领域组织

src/main/java/com/company/
├── order/          # 订单领域
├── inventory/      # 库存领域
├── payment/        # 支付领域
└── customer/       # 客户领域

分层清晰

  • 领域层:纯业务逻辑,不依赖外部
  • 应用层:协调领域对象,处理用例
  • 基础设施层:技术实现,数据持久化
  • 接口层:对外暴露API

3. 测试策略

单元测试

@Test
public void should_confirm_order_when_status_is_pending() {// GivenOrder order = Order.create(customerId, orderItems, shippingAddress);// Whenorder.confirm();// ThenassertThat(order.getStatus()).isEqualTo(OrderStatus.CONFIRMED);assertThat(order.getDomainEvents()).hasSize(1);assertThat(order.getDomainEvents().get(0)).isInstanceOf(OrderConfirmedEvent.class);
}

集成测试

@SpringBootTest
@Transactional
public class OrderApplicationServiceTest {@Testpublic void should_create_order_successfully() {// GivenCreateOrderCommand command = buildCreateOrderCommand();// WhenCreateOrderResult result = orderApplicationService.createOrder(command);// ThenassertThat(result.getOrderId()).isNotNull();// 验证数据库状态Order savedOrder = orderRepository.findById(OrderId.of(result.getOrderId())).get();assertThat(savedOrder.getStatus()).isEqualTo(OrderStatus.PENDING);}
}

🎯 总结:DDD的价值与未来

DDD不仅仅是一种技术实践,更是一种思维方式的转变。

记住:DDD的核心价值在于让技术更好地服务于业务,让复杂的业务逻辑变得清晰可控。好的领域模型应该是业务专家和技术专家都能理解的共同语言。

http://www.lryc.cn/news/615187.html

相关文章:

  • Typora上传图片保存到assets目录下
  • 第十四届蓝桥杯青少年组省赛 编程题真题题解
  • stm32项目(24)——基于STM32的汽车CAN通信系统
  • WinForm 复合控件(用户控件):创建与使用指南
  • 深入 FastMCP 源码:认识 tool()、resource() 和 prompt() 装饰器
  • sqli-labs通关笔记-第39关 GET数值型堆叠注入(手工注入+脚本注入两种方法)
  • 数据分析框架从 “工具堆砌” 转向 “智能协同”
  • 大语言模型提示工程与应用:提示工程-提升模型准确性与减少偏见的方法
  • node.js 零基础入门
  • 学习嵌入式第二十四天
  • Kotlin 协程线程切换机制详解
  • M8-11 RFID模块通过RS485转Profinet网关与PLC通信的配置指南
  • 安装NodeJS和TypeScript简要指南
  • 虚拟机远程连接报错解决办法
  • 「iOS」————分类与扩展
  • 书生浦语第五期-L1G4-InternLM 论文分类微调实践(XTuner 版)
  • 代码随想录day60图论10
  • 快速使用selenium+java案例
  • Nginx 性能优化与动态内容处理
  • TOMCAT笔记
  • 七、《Serverless架构:按毫秒计费的成本革命》--从新浪AI推理平台50%效能提升看无服务器本质
  • 前端如何安全存储 API 密钥 —— 两种实用方案
  • CosyVoice 语音合成模型性能优化实战:从 CPU 瓶颈到 GPU 加速的完整解决方案
  • electron多进程设计
  • K8s-pod控制器
  • Baumer高防护相机如何通过YoloV8深度学习模型实现输电线路塔电缆检测分割(C#代码UI界面版)
  • DAY 37 作业(补)
  • 99-基于Python的京东手机数据分析及预测系统
  • 【工具变量】全国省级农业保险保费收入与赔付支出数据更新(2001-2023年)
  • 爬虫攻防战:反爬与反反爬全解析