第5章:领域服务(Domain Services)
一、导读
1.1 本章学习目标
第5章讲解领域服务——不属于任何实体的业务操作。
本章的核心学习目标包括:
- 理解领域服务和应用服务的区别
- 掌握领域服务的设计原则
- 学会使用工厂模式创建复杂对象
- 理解仓储(Repository)的职责
1.2 为什么本章如此重要
不是所有业务逻辑都适合放在实体或值对象中。领域服务处理那些涉及多个对象、不属于任何单一实体的业务操作。正确识别和放置领域服务,能让模型更加清晰。
1.3 核心问题引导
领域服务和应用服务有什么区别?
什么业务逻辑应该放在领域服务中?
工厂模式在 DDD 中如何使用?
仓储的职责是什么?它和 DAO 有什么区别?
二、核心概念详解
2.1 领域服务 vs 应用服务
java
// 领域服务:封装不属于任何实体的业务逻辑
public class TransferService {
public void transfer(Account from, Account to, Money amount) {
// 涉及两个聚合的业务逻辑
from.debit(amount);
to.credit(amount);
}
}
// 应用服务:协调领域对象完成用例
public class TransferApplicationService {
private AccountRepository accountRepo;
private TransferService transferService; // 领域服务
public void transfer(TransferCommand cmd) {
Account from = accountRepo.findById(cmd.getFromId());
Account to = accountRepo.findById(cmd.getToId());
transferService.transfer(from, to, cmd.getAmount());
accountRepo.save(from);
accountRepo.save(to);
}
}2.2 工厂
java
// 工厂:封装复杂对象的创建逻辑
public class OrderFactory {
private ProductRepository productRepo;
public Order createOrder(CustomerId customerId, List<OrderLineRequest> lines) {
Order order = new Order(customerId);
for (OrderLineRequest line : lines) {
Product product = productRepo.findById(line.getProductId());
order.addLine(product, line.getQuantity());
}
return order;
}
}2.3 仓储
java
// 仓储:聚合的持久化抽象
public interface OrderRepository {
Order findById(OrderId id);
void save(Order order);
void remove(Order order);
List<Order> findByCustomerId(CustomerId customerId);
}
// 实现
public class JpaOrderRepository implements OrderRepository {
private EntityManager em;
@Override
public Order findById(OrderId id) {
return em.find(Order.class, id.getValue());
}
@Override
public void save(Order order) {
em.merge(order);
}
}三、实战案例
3.1 案例一:转账领域服务
java
public class MoneyTransferService {
private final ExchangeRateProvider exchangeRateProvider;
public TransferResult transfer(
Account from, Account to, Money amount, Currency targetCurrency
) {
// 跨币种转账的业务逻辑
Money sourceAmount;
if (amount.getCurrency().equals(targetCurrency)) {
sourceAmount = amount;
} else {
ExchangeRate rate = exchangeRateProvider.getRate(
amount.getCurrency(), targetCurrency
);
sourceAmount = rate.convert(amount);
}
from.debit(sourceAmount);
to.credit(amount);
return new TransferResult(sourceAmount, amount);
}
}四、本章小结
领域服务:封装不属于任何实体的业务逻辑。
应用服务:协调领域对象完成用例。
工厂:封装复杂对象的创建。
仓储:聚合的持久化抽象。
五、思考与练习
在一个银行系统中识别领域服务和应用服务。
设计一个工厂来创建包含多个聚合的复杂对象。
仓储和 DAO 有什么区别?