DDD 领域驱动设计实战:从理论到代码
DDD 领域驱动设计实战从理论到代码别叫我大神叫我 Alex 就好。DDD 不是银弹但它是处理复杂业务逻辑的利器。一、DDD 核心概念1.1 分层架构┌─────────────────────────────────────────┐ │ User Interface │ │ - Controller / DTO / Validator │ └──────────────┬──────────────────────────┘ │ ┌──────────────▼──────────────────────────┐ │ Application │ │ - Service / Use Case / Event │ └──────────────┬──────────────────────────┘ │ ┌──────────────▼──────────────────────────┐ │ Domain │ │ - Entity / Value Object / Aggregate │ │ - Domain Service / Repository │ └──────────────┬──────────────────────────┘ │ ┌──────────────▼──────────────────────────┐ │ Infrastructure │ │ - Persistence / Message / External │ └─────────────────────────────────────────┘1.2 项目结构com.example.order ├── application │ ├── dto │ │ ├── OrderDTO.java │ │ └── OrderItemDTO.java │ ├── event │ │ └── OrderEventPublisher.java │ ├── service │ │ └── OrderApplicationService.java │ └── mapper │ └── OrderMapper.java ├── domain │ ├── model │ │ ├── entity │ │ │ ├── Order.java │ │ │ └── OrderItem.java │ │ ├── valueobject │ │ │ ├── Address.java │ │ │ ├── Money.java │ │ │ └── OrderStatus.java │ │ └── aggregate │ │ └── OrderAggregate.java │ ├── service │ │ └── OrderDomainService.java │ ├── repository │ │ └── OrderRepository.java │ └── event │ ├── OrderCreatedEvent.java │ └── OrderPaidEvent.java ├── infrastructure │ ├── persistence │ │ ├── JpaOrderRepository.java │ │ └── entity │ │ ├── OrderPO.java │ │ └── OrderItemPO.java │ └── messaging │ └── KafkaEventPublisher.java └── interfaces ├── rest │ └── OrderController.java └── mq └── OrderEventListener.java二、领域模型实现2.1 实体与值对象// 值对象 - 地址 Value public class Address { private final String province; private final String city; private final String district; private final String detail; private final String zipCode; public Address(String province, String city, String district, String detail, String zipCode) { // 校验逻辑 if (StringUtils.isBlank(province)) { throw new IllegalArgumentException(Province cannot be empty); } this.province province; this.city city; this.district district; this.detail detail; this.zipCode zipCode; } // 值对象比较基于内容 Override public boolean equals(Object o) { if (this o) return true; if (o null || getClass() ! o.getClass()) return false; Address address (Address) o; return Objects.equals(province, address.province) Objects.equals(city, address.city) Objects.equals(district, address.district) Objects.equals(detail, address.detail); } Override public int hashCode() { return Objects.hash(province, city, district, detail); } } // 值对象 - 金额 Value public class Money { private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { if (amount.compareTo(BigDecimal.ZERO) 0) { throw new IllegalArgumentException(Amount cannot be negative); } this.amount amount; this.currency currency; } public Money add(Money other) { if (this.currency ! other.currency) { throw new IllegalArgumentException(Cannot add different currencies); } return new Money(this.amount.add(other.amount), this.currency); } public Money multiply(int factor) { return new Money(this.amount.multiply(BigDecimal.valueOf(factor)), this.currency); } } // 实体 - 订单 Entity public class Order extends BaseAggregateRootOrderId { private OrderId id; private CustomerId customerId; private ListOrderItem items; private Money totalAmount; private Address shippingAddress; private OrderStatus status; private LocalDateTime createTime; // 工厂方法 public static Order create(CustomerId customerId, ListOrderItem items, Address shippingAddress) { Order order new Order(); order.id OrderId.generate(); order.customerId customerId; order.items new ArrayList(items); order.shippingAddress shippingAddress; order.status OrderStatus.CREATED; order.createTime LocalDateTime.now(); order.calculateTotalAmount(); // 发布领域事件 order.registerEvent(new OrderCreatedEvent(order.id, order.totalAmount)); return order; } // 领域行为 public void pay(Payment payment) { if (status ! OrderStatus.CREATED) { throw new IllegalStateException(Order can only be paid when created); } if (!payment.getAmount().equals(this.totalAmount)) { throw new IllegalArgumentException(Payment amount does not match); } this.status OrderStatus.PAID; this.registerEvent(new OrderPaidEvent(this.id, payment.getAmount())); } public void ship(TrackingNumber trackingNumber) { if (status ! OrderStatus.PAID) { throw new IllegalStateException(Order must be paid before shipping); } this.status OrderStatus.SHIPPED; this.registerEvent(new OrderShippedEvent(this.id, trackingNumber)); } public void cancel() { if (status OrderStatus.SHIPPED || status OrderStatus.DELIVERED) { throw new IllegalStateException(Cannot cancel shipped or delivered order); } this.status OrderStatus.CANCELLED; this.registerEvent(new OrderCancelledEvent(this.id)); } private void calculateTotalAmount() { this.totalAmount items.stream() .map(OrderItem::getSubtotal) .reduce(Money.ZERO, Money::add); } // 业务规则校验 public boolean canBeModified() { return status OrderStatus.CREATED; } }2.2 聚合根// 聚合根 public class Order extends BaseAggregateRootOrderId { // 聚合内部实体 private ListOrderItem items new ArrayList(); // 聚合内部值对象 private ShippingAddress shippingAddress; private PaymentInfo paymentInfo; // 只能通过聚合根修改内部实体 public void addItem(Product product, int quantity, Money price) { // 业务规则 if (items.size() 20) { throw new IllegalArgumentException(Order cannot have more than 20 items); } OrderItem item new OrderItem(product.getId(), quantity, price); items.add(item); recalculateTotal(); } public void removeItem(int itemIndex) { if (itemIndex 0 || itemIndex items.size()) { throw new IllegalArgumentException(Invalid item index); } items.remove(itemIndex); recalculateTotal(); } // 保证聚合不变量 private void recalculateTotal() { this.totalAmount items.stream() .map(item - item.getPrice().multiply(item.getQuantity())) .reduce(Money.ZERO, Money::add); } } // 聚合根仓储接口 public interface OrderRepository { Order findById(OrderId id); void save(Order order); ListOrder findByCustomerId(CustomerId customerId); }三、领域服务// 领域服务 - 处理跨聚合的业务逻辑 Service public class OrderDomainService { Autowired private InventoryService inventoryService; Autowired private PricingService pricingService; // 创建订单的复杂业务逻辑 public Order createOrder(CustomerId customerId, ListOrderItemRequest itemRequests) { // 检查库存 for (OrderItemRequest request : itemRequests) { if (!inventoryService.isAvailable(request.getProductId(), request.getQuantity())) { throw new InsufficientStockException(request.getProductId()); } } // 计算价格 ListOrderItem items itemRequests.stream() .map(request - { Money price pricingService.calculatePrice( request.getProductId(), request.getQuantity() ); return new OrderItem(request.getProductId(), request.getQuantity(), price); }) .collect(Collectors.toList()); // 创建订单 Order order Order.create(customerId, items); // 预留库存 for (OrderItem item : items) { inventoryService.reserve(item.getProductId(), item.getQuantity()); } return order; } // 订单合并 public Order mergeOrders(ListOrder orders) { if (orders.size() 2) { throw new IllegalArgumentException(Need at least 2 orders to merge); } CustomerId customerId orders.get(0).getCustomerId(); // 验证所有订单属于同一客户 boolean sameCustomer orders.stream() .allMatch(o - o.getCustomerId().equals(customerId)); if (!sameCustomer) { throw new IllegalArgumentException(Can only merge orders from same customer); } // 合并商品项 ListOrderItem mergedItems orders.stream() .flatMap(o - o.getItems().stream()) .collect(Collectors.toList()); // 创建新订单 return Order.create(customerId, mergedItems); } }四、应用服务Service Transactional public class OrderApplicationService { Autowired private OrderRepository orderRepository; Autowired private OrderDomainService orderDomainService; Autowired private OrderEventPublisher eventPublisher; Autowired private OrderMapper orderMapper; // 用例创建订单 public OrderDTO createOrder(CreateOrderCommand
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2466000.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!