项目

领域服务最佳实践与规范

本文档基于领域驱动设计原则,为模块和应用程序中实现领域服务类提供最佳实践。

请确保您已阅读 领域服务 文档。

领域服务

  • 应当领域层中定义领域服务。
  • 不应为领域服务创建接口,除非有充分理由(例如模拟和测试不同的实现)。
  • 应当使用 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的相关数据。

另请参阅

在本文档中