Domain driven design DDD中服务的对与错

Domain driven design DDD中服务的对与错,domain-driven-design,Domain Driven Design,如果我错了,请纠正我(并添加您认为正确的其他内容): 应用程序服务 域的(面向公众的)api 负责装载和保存骨料 可以访问存储库和其他基础结构服务 不是通用语言的一部分 应该/可能是域顶部非常薄的一层(主要处理聚合的加载/保存,并将其余部分委托给域) 可以包含纯读取操作 域服务 域的“真实”api 包含域逻辑 仅适用于域对象(不适用于基础结构服务,如repos和电子邮件发件人服务) 通常包含编排不同聚合的代码 是通用语言的一部分 可以依赖于其他域服务 只包含修改操作 我相信您对域服务的理解

如果我错了,请纠正我(并添加您认为正确的其他内容):

应用程序服务

  • 域的(面向公众的)api
  • 负责装载和保存骨料
  • 可以访问存储库和其他基础结构服务
  • 不是通用语言的一部分
  • 应该/可能是域顶部非常薄的一层(主要处理聚合的加载/保存,并将其余部分委托给域)
  • 可以包含纯读取操作
域服务

  • 域的“真实”api
  • 包含域逻辑
  • 仅适用于域对象(不适用于基础结构服务,如repos和电子邮件发件人服务)
  • 通常包含编排不同聚合的代码
  • 是通用语言的一部分
  • 可以依赖于其他域服务
  • 只包含修改操作

我相信您对
域服务的理解是不正确的

正确的起点将是Eric Evans的域驱动设计的第5章,他在其中定义了
值对象
实体
域服务

据我所知,Evans的模式基于2003年左右使用Java编写领域模型的经验。在Java中,任何不是域不可知原语的东西都是“对象”;虽然可以实现静态函数,但没有任何特别好的方法来传递它们。相反,您需要将函数包装在对象内部

所以“域服务”是“无状态对象”;对象,因为这是传递它们时的一个约束,而无状态,因为底层数据的所有变化都是管理该数据的实体的责任

在本文中,我相信他使用了税收表的例子;发票需要能够正确计算税款,但税款代码不由发票实例拥有或管理;相反,该数据在别处管理,并且只读副本由模型中的所有发票共享

在Cargo shipping示例中,需要将货物指定给路线,但货物实体不管理自己的装运计划副本。相反,“RoutingService”支持对这些表的查询


罗伯特·马丁(Robert Martin)所说的实体协调是一个应用程序问题,而不是由域服务(如Evans所述)管理的问题。

您对应用程序服务的定义是正确的。我将应用程序服务更多地视为命令处理程序。接收命令,加载聚合,调用聚合方法并保存机会。一个命令在单个事务中处理

域服务用于执行聚合需要但无法执行的操作。典型的例子可能是从外部世界检索额外的信息或进行一些计算。应用程序服务不一定知道聚合是否需要这个或那个信息,但它可以解决必要的依赖关系,并在调用聚合时将域服务传递给聚合

在我的实践中,域服务通常作为函数实现。请记住,域服务并非仅由聚合使用。复杂值对象可以完美地将域服务用于相同的目的

在我的书中,我使用了一个域服务来允许a来确保它不会被包含亵渎内容的文本实例化

    public static DisplayName FromString(
        string displayName,
        CheckTextForProfanity hasProfanity)
    {
        if (displayName.IsEmpty())
            throw new ArgumentNullException(nameof(FullName));

        if (hasProfanity(displayName).GetAwaiter().GetResult())
            throw new DomainExceptions.ProfanityFound(displayName);

        return new DisplayName(displayName);
    }
因此,域服务契约(在这种情况下为命名委托)在域中定义

namespace Marketplace.Domain.Shared
{
    public delegate Task<bool> CheckTextForProfanity(string text);
}
namespace Marketplace.Domain.Shared
{
公共委托任务检查文本是否亵渎(字符串文本);
}
但它的实现是基础设施方面的问题,并且正在应用程序端进行连接

namespace Marketplace.Infrastructure
{
    /// <summary>
    /// PurgoMalum is a simple, free, RESTful web service for filtering and removing content of profanity, obscenity and other unwanted text.
    /// Check http://www.purgomalum.com
    /// </summary>
    public class PurgomalumClient
    {
        private readonly HttpClient _httpClient;

        public PurgomalumClient() : this(new HttpClient()) { }

        public PurgomalumClient(HttpClient httpClient) => _httpClient = httpClient;

        public async Task<bool> CheckForProfanity(string text)
        {
            var result = await _httpClient.GetAsync(
                QueryHelpers.AddQueryString("https://www.purgomalum.com/service/containsprofanity", "text", text));

            var value = await result.Content.ReadAsStringAsync();
            return bool.Parse(value);
        }
    }
}
名称空间市场.基础架构
{
/// 
///PurgoMalum是一个简单、免费、RESTful的web服务,用于过滤和删除亵渎、淫秽和其他不需要的文本内容。
///检查http://www.purgomalum.com
/// 
公共类PurgomalumClient
{
私有只读HttpClientu HttpClient;
public PurgomalumClient():这个(新的HttpClient()){}
公共PurgomalumClient(HttpClient HttpClient)=>\u HttpClient=HttpClient;
公共异步任务检查亵渎(字符串文本)
{
var result=await\u httpClient.GetAsync(
QueryHelpers.AddQueryString(“https://www.purgomalum.com/service/containsprofanity“,”文本“,”文本“);
var value=wait result.Content.ReadAsStringAsync();
返回bool.Parse(值);
}
}
}