5Implementing Domain-Driven Design

领域服务

领域逻辑

领域服务应用服务工厂仓储

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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 有什么区别?


5/7领域服务
0%