第501集DDD
|字数总计:2.7k|阅读时长:12分钟|阅读量:
DDD
1. 概述
1.1 DDD的重要性
DDD(Domain-Driven Design,领域驱动设计)是一种软件设计方法论,通过深入理解业务领域,构建反映业务本质的领域模型,从而设计出更好的软件系统。
本文内容:
- DDD基础:核心概念和设计思想
- 战略设计:限界上下文、上下文映射
- 战术设计:实体、值对象、聚合、领域服务
- 领域模型:领域模型设计方法
- 实战案例:DDD实战应用
1.2 本文内容结构
本文将从以下几个方面深入探讨DDD:
- DDD基础:核心概念和设计思想
- 战略设计:限界上下文、上下文映射
- 战术设计:实体、值对象、聚合、领域服务
- 领域模型:领域模型设计方法
- 实战案例:DDD实战应用
2. DDD基础
2.1 DDD核心概念
2.1.1 领域和子领域
领域(Domain):业务领域,软件要解决的业务问题。
子领域(Subdomain):
- 核心域(Core Domain):业务的核心竞争力
- 支撑域(Supporting Domain):支撑核心域的业务
- 通用域(Generic Domain):通用业务功能
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class ECommerceDomain { public class OrderDomain { } public class InventoryDomain { } public class AuthenticationDomain { } }
|
2.2 统一语言
2.2.1 统一语言概念
统一语言(Ubiquitous Language):开发人员和业务人员共同使用的语言。
统一语言示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Order { private String orderNo; private OrderStatus status; private List<OrderItem> items; public void confirm() { } public void cancel() { } public void ship() { } }
|
3. 战略设计
3.1 限界上下文
3.1.1 限界上下文概念
限界上下文(Bounded Context):领域模型的边界,在边界内,所有术语和概念都有明确的含义。
限界上下文示例:
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 31
| @BoundedContext("Order") public class OrderContext { public class Order { private String orderNo; private Customer customer; private List<OrderItem> items; } public class OrderItem { private Product product; private int quantity; } }
@BoundedContext("Inventory") public class InventoryContext { public class Stock { private String productId; private int quantity; } public class StockMovement { private String productId; private int quantity; private MovementType type; } }
|
3.2 上下文映射
3.2.1 上下文关系
上下文映射:描述不同限界上下文之间的关系。
上下文关系类型:
- 共享内核(Shared Kernel):共享部分模型
- 客户-供应商(Customer-Supplier):上游下游关系
- 遵奉者(Conformist):完全遵循上游模型
- 防腐层(Anticorruption Layer):隔离外部系统
- 独立方式(Separate Ways):完全独立
上下文映射示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @BoundedContext("Order") public class OrderContext { @AnticorruptionLayer public class InventoryAdapter { private InventoryService inventoryService; public boolean checkStock(String productId, int quantity) { return inventoryService.hasStock(productId, quantity); } } }
|
4. 战术设计
4.1 实体(Entity)
4.1.1 实体概念
实体(Entity):有唯一标识的对象,通过ID区分。
实体示例:
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 31 32 33 34 35 36 37
| public class Order { private Long id; private String orderNo; private Customer customer; private List<OrderItem> items; private OrderStatus status; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Order order = (Order) o; return Objects.equals(id, order.id); } @Override public int hashCode() { return Objects.hash(id); } public void confirm() { if (status != OrderStatus.CREATED) { throw new IllegalStateException("Order cannot be confirmed"); } this.status = OrderStatus.CONFIRMED; } public void cancel() { if (status == OrderStatus.SHIPPED) { throw new IllegalStateException("Cannot cancel shipped order"); } this.status = OrderStatus.CANCELLED; } }
|
4.2 值对象(Value Object)
4.2.1 值对象概念
值对象(Value Object):没有唯一标识,通过属性值区分。
值对象示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| public class Money { private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = amount; this.currency = currency; } @Override public 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); } @Override public int hashCode() { return Objects.hash(amount, currency); } public Money add(Money other) { if (!currency.equals(other.currency)) { throw new IllegalArgumentException("Currency mismatch"); } return new Money(amount.add(other.amount), currency); } public Money multiply(int multiplier) { return new Money(amount.multiply(BigDecimal.valueOf(multiplier)), currency); } }
public class Address { private final String street; private final String city; private final String zipCode; public Address(String street, String city, String zipCode) { this.street = street; this.city = city; 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(street, address.street) && Objects.equals(city, address.city) && Objects.equals(zipCode, address.zipCode); } @Override public int hashCode() { return Objects.hash(street, city, zipCode); } }
|
4.3 聚合(Aggregate)
4.3.1 聚合概念
聚合(Aggregate):一组相关对象的集合,有聚合根。
聚合根(Aggregate Root):聚合的入口,外部只能通过聚合根访问聚合。
聚合示例:
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 31 32 33 34 35 36 37 38 39
| public class OrderAggregate { private Order order; private List<OrderItem> items; public OrderAggregate(Order order) { this.order = order; this.items = new ArrayList<>(); } public void addItem(Product product, int quantity) { if (order.getStatus() != OrderStatus.CREATED) { throw new IllegalStateException("Cannot add item to non-created order"); } OrderItem item = new OrderItem(product, quantity); items.add(item); order.calculateTotal(); } public void removeItem(OrderItem item) { if (order.getStatus() != OrderStatus.CREATED) { throw new IllegalStateException("Cannot remove item from non-created order"); } items.remove(item); order.calculateTotal(); } public void confirm() { order.confirm(); DomainEventPublisher.publish(new OrderConfirmedEvent(order.getId())); } }
|
4.4 领域服务(Domain Service)
4.4.1 领域服务概念
领域服务(Domain Service):不属于任何实体的业务逻辑。
领域服务示例:
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
| @Service public class OrderNumberGenerator { public String generate() { return "ORD" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(4); } }
@Service public class PriceCalculationService { public Money calculateTotal(List<OrderItem> items, Discount discount) { Money subtotal = items.stream() .map(OrderItem::getSubtotal) .reduce(Money.ZERO, Money::add); if (discount != null) { Money discountAmount = discount.calculateDiscount(subtotal); return subtotal.subtract(discountAmount); } return subtotal; } }
|
4.5 领域事件(Domain Event)
4.5.1 领域事件概念
领域事件(Domain 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 31 32 33 34 35 36 37 38 39 40 41 42
| public interface DomainEvent { Date occurredOn(); }
public class OrderConfirmedEvent implements DomainEvent { private Long orderId; private Date occurredOn; public OrderConfirmedEvent(Long orderId) { this.orderId = orderId; this.occurredOn = new Date(); } @Override public Date occurredOn() { return occurredOn; } }
public class DomainEventPublisher { private static final ThreadLocal<List<DomainEvent>> events = new ThreadLocal<>(); public static void publish(DomainEvent event) { List<DomainEvent> eventList = events.get(); if (eventList == null) { eventList = new ArrayList<>(); events.set(eventList); } eventList.add(event); } public static List<DomainEvent> getEvents() { return events.get(); } public static void clear() { events.remove(); } }
|
5. 仓储(Repository)
5.1 仓储概念
5.1.1 仓储模式
仓储(Repository):封装聚合的持久化逻辑。
仓储示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public interface OrderRepository { void save(OrderAggregate order); OrderAggregate findById(Long id); List<OrderAggregate> findByCustomerId(Long customerId); void delete(Long id); }
@Repository public class OrderRepositoryImpl implements OrderRepository { @Autowired private OrderMapper orderMapper; @Autowired private OrderItemMapper orderItemMapper; @Override public void save(OrderAggregate order) { Order orderEntity = order.getOrder(); if (orderEntity.getId() == null) { orderMapper.insert(orderEntity); } else { orderMapper.update(orderEntity); } for (OrderItem item : order.getItems()) { if (item.getId() == null) { orderItemMapper.insert(item); } else { orderItemMapper.update(item); } } } @Override public OrderAggregate findById(Long id) { Order order = orderMapper.findById(id); if (order == null) { return null; } List<OrderItem> items = orderItemMapper.findByOrderId(id); return new OrderAggregate(order, items); } }
|
6. 应用服务(Application Service)
6.1 应用服务概念
6.1.1 应用服务
应用服务(Application Service):协调领域对象完成用例。
应用服务示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| @Service public class OrderApplicationService { @Autowired private OrderRepository orderRepository; @Autowired private OrderNumberGenerator orderNumberGenerator; @Autowired private PriceCalculationService priceCalculationService; @Autowired private DomainEventPublisher eventPublisher; @Transactional public OrderDTO createOrder(CreateOrderRequest request) { String orderNo = orderNumberGenerator.generate(); Order order = new Order(orderNo, request.getCustomerId()); OrderAggregate orderAggregate = new OrderAggregate(order); for (OrderItemRequest itemRequest : request.getItems()) { Product product = productService.findById(itemRequest.getProductId()); orderAggregate.addItem(product, itemRequest.getQuantity()); } Money total = priceCalculationService.calculateTotal( orderAggregate.getItems(), request.getDiscount() ); order.setTotalAmount(total); orderRepository.save(orderAggregate); eventPublisher.publish(new OrderCreatedEvent(order.getId())); return OrderDTO.from(order); } @Transactional public void confirmOrder(Long orderId) { OrderAggregate orderAggregate = orderRepository.findById(orderId); if (orderAggregate == null) { throw new OrderNotFoundException(); } orderAggregate.confirm(); orderRepository.save(orderAggregate); } }
|
7. 实战案例
7.1 电商订单系统
7.1.1 DDD设计
电商订单系统DDD设计:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| public class Order { private Long id; private String orderNo; private CustomerId customerId; private Address shippingAddress; private List<OrderItem> items; private Money totalAmount; private OrderStatus status; private LocalDateTime createTime; public Order(String orderNo, CustomerId customerId) { this.orderNo = orderNo; this.customerId = customerId; this.items = new ArrayList<>(); this.status = OrderStatus.CREATED; this.createTime = LocalDateTime.now(); } public void addItem(Product product, int quantity) { if (status != OrderStatus.CREATED) { throw new IllegalStateException("Cannot add item to non-created order"); } OrderItem item = new OrderItem(product, quantity); items.add(item); calculateTotal(); } private void calculateTotal() { totalAmount = items.stream() .map(OrderItem::getSubtotal) .reduce(Money.ZERO, Money::add); } public void confirm() { if (status != OrderStatus.CREATED) { throw new IllegalStateException("Order cannot be confirmed"); } this.status = OrderStatus.CONFIRMED; } public void pay() { if (status != OrderStatus.CONFIRMED) { throw new IllegalStateException("Order cannot be paid"); } this.status = OrderStatus.PAID; } public void ship() { if (status != OrderStatus.PAID) { throw new IllegalStateException("Order cannot be shipped"); } this.status = OrderStatus.SHIPPED; } public void cancel() { if (status == OrderStatus.SHIPPED) { throw new IllegalStateException("Cannot cancel shipped order"); } this.status = OrderStatus.CANCELLED; } }
public class OrderItem { private Long id; private Product product; private int quantity; private Money price; public OrderItem(Product product, int quantity) { this.product = product; this.quantity = quantity; this.price = product.getPrice(); } public Money getSubtotal() { return price.multiply(quantity); } }
|
8. 总结
8.1 核心要点
- 战略设计:限界上下文、上下文映射
- 战术设计:实体、值对象、聚合、领域服务
- 统一语言:开发人员和业务人员共同使用
- 领域模型:反映业务本质的模型
8.2 关键理解
- 以业务为中心:深入理解业务领域
- 模型驱动:通过领域模型驱动设计
- 边界清晰:限界上下文明确边界
- 聚合设计:合理设计聚合和聚合根
8.3 最佳实践
- 深入理解业务:与业务人员密切沟通
- 使用统一语言:代码反映业务语言
- 合理划分聚合:聚合不要过大
- 领域事件:使用领域事件解耦
相关文章: