领域服务
模型中的领域服务表示一个无状态的操作,他用于实现特定于某个领域的任务。 当领域中某个操作过程或转化过程不是实体或值对象的职责时,我们便应该将该操作放在一个单独的元素中,即领域服务。同时务必保持该领域服务与通用语言是一致的,并且保证它是无状态的。
领域服务的特征
- 它代表领域概念。
- 它与通用语言保存一致,其中包括命名和内部逻辑。
- 它无状态。
- 领域服务与聚合在同一包中。
何时使用领域服务
如果某操作不适合放在聚合和值对象上时,最好的方式便是将其建模成领域服务。
为避免贫血模型,在封装领域逻辑时,考虑设计要素的顺序为:
Value Object -> Entity -> Domain Service
只有满足如下三个特征的领域行为才应该放到领域服务中:
- 领域行为需要多个领域实体参与协作
- 领域行为与状态无关
- 领域行为需要与外部资源(尤其是DB)协作
代码示例
领域服务的执行一般会涉及实体或值对象,在其基础之上将行为封装成业务概念。
比较常见的就是银行转账,首先银行转账具有明显的领域概念,其次,由于同时涉及两个账号,该行为放在账号聚合中不太合适。因此,可以将其建模成领域服务。
public class Account extends JpaAggregate {
private Long totalAmount;
public void checkBalance(Long amount) {
if (amount > this.totalAmount){
throw new IllegalArgumentException("余额不足");
}
}
public void reduce(Long amount) {
this.totalAmount = this.totalAmount - amount;
}
public void increase(Long amount) {
this.totalAmount = this.totalAmount + amount;
}
}
Account 提供余额检测、扣除和添加等基本功能。
public class TransferService implements DomainService {
public void transfer(Account from, Account to, Long amount){
from.checkBalance(amount);
from.reduce(amount);
to.increase(amount);
}
}
TransferService 按照业务规则,指定转账流程。
TransferService 明确定义了一个存在于通用语言的一个领域概念。领域服务存在于领域模型中,包含重要的业务规则。