DDD

1. 概述

1.1 DDD的重要性

DDD(Domain-Driven Design,领域驱动设计)是一种软件设计方法论,通过深入理解业务领域,构建反映业务本质的领域模型,从而设计出更好的软件系统。

本文内容

  • DDD基础:核心概念和设计思想
  • 战略设计:限界上下文、上下文映射
  • 战术设计:实体、值对象、聚合、领域服务
  • 领域模型:领域模型设计方法
  • 实战案例:DDD实战应用

1.2 本文内容结构

本文将从以下几个方面深入探讨DDD:

  1. DDD基础:核心概念和设计思想
  2. 战略设计:限界上下文、上下文映射
  3. 战术设计:实体、值对象、聚合、领域服务
  4. 领域模型:领域模型设计方法
  5. 实战案例: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 {
// 订单(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;

// 实体通过ID相等性判断
@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) {
// 1. 创建订单聚合
String orderNo = orderNumberGenerator.generate();
Order order = new Order(orderNo, request.getCustomerId());
OrderAggregate orderAggregate = new OrderAggregate(order);

// 2. 添加订单项
for (OrderItemRequest itemRequest : request.getItems()) {
Product product = productService.findById(itemRequest.getProductId());
orderAggregate.addItem(product, itemRequest.getQuantity());
}

// 3. 计算总价
Money total = priceCalculationService.calculateTotal(
orderAggregate.getItems(),
request.getDiscount()
);
order.setTotalAmount(total);

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

// 5. 发布领域事件
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 核心要点

  1. 战略设计:限界上下文、上下文映射
  2. 战术设计:实体、值对象、聚合、领域服务
  3. 统一语言:开发人员和业务人员共同使用
  4. 领域模型:反映业务本质的模型

8.2 关键理解

  1. 以业务为中心:深入理解业务领域
  2. 模型驱动:通过领域模型驱动设计
  3. 边界清晰:限界上下文明确边界
  4. 聚合设计:合理设计聚合和聚合根

8.3 最佳实践

  1. 深入理解业务:与业务人员密切沟通
  2. 使用统一语言:代码反映业务语言
  3. 合理划分聚合:聚合不要过大
  4. 领域事件:使用领域事件解耦

相关文章