领域服务最佳实践与规范
本文档基于领域驱动设计原则,为模块和应用程序中实现领域服务类提供最佳实践。
请确保您已阅读 领域服务 文档。
领域服务
- 应当在领域层中定义领域服务。
- 不应为领域服务创建接口,除非有充分理由(例如模拟和测试不同的实现)。
- 应当使用
Manager后缀命名领域服务。
示例领域服务:
public class IssueManager : DomainService
{
//...
}
领域服务方法
不应定义
GET方法。GET方法不改变实体状态。因此,直接在应用服务中使用仓储,而非通过领域服务方法。应当定义仅用于变更数据的方法;即改变实体或聚合根的状态。
不应定义具有通用名称的方法(如
UpdateIssueAsync)。应当定义具有自解释性名称的方法(如
AssignToAsync),实现特定的领域逻辑。应当接受有效的领域对象作为参数。
public async Task AssignToAsync(Issue issue, IdentityUser user)
{
//...
}
应当在验证失败时抛出
BusinessException或自定义业务异常。- 应当使用带有唯一代码命名空间的领域错误码,以便异常本地化。
public async Task AssignToAsync(Issue issue, IdentityUser user)
{
var openIssueCount = await _issueRepository.GetCountAsync(
i => i.AssignedUserId == user.Id && !i.IsClosed
);
if (openIssueCount >= 3)
{
throw new BusinessException("IssueTracking:ConcurrentOpenIssueLimit");
}
issue.AssignedUserId = user.Id;
}
- 不应返回
DTO。仅在需要时返回领域对象。 - 不应涉及认证用户逻辑。相反,应定义额外参数,并从应用服务层传递
CurrentUser的相关数据。
抠丁客


