当前位置:  开发笔记 > 编程语言 > 正文

域驱动设计:域服务,应用服务

如何解决《域驱动设计:域服务,应用服务》经验,为你挑选了6个好方法。

有人可以通过提供一些示例来解释域和应用程序服务之间的区别吗?并且,如果服务是域服务,我是否会将此服务的实际实现放在域程序集中?如果是,我是否也会将存储库注入该域服务?一些信息会非常有用.



1> Vijay Patel..:

服务有三种形式:域服务,应用服务基础设施服务.

域服务:封装 不自然地适合域对象的业务逻辑,并且不是典型的CRUD操作 - 那些属于存储库.

应用程序服务:由外部使用者用于与您的系统通信(想想Web服务).如果消费者需要访问CRUD操作,他们就会在这里公开.

基础设施服务:用于抽象技术问题(例如MSMQ,电子邮件提供商等).

保持域服务和域对象是明智的 - 它们都专注于域逻辑.是的,您可以将存储库注入您的服务.

Application Services通常使用域服务存储库来处理外部请求.

希望有所帮助!


我认为应用服务应该独立于"Web服务"之类的技术细节,它们被这些服务使用.请参阅[域驱动设计中的服务](http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/)
你会把CQRS的命令和查询放在哪里?哪个服务生成它们以及哪个服务处理它们?

2> Niels van de..:

(如果你不想阅读,底部有一个摘要:-)

我也一直在努力精确定义应用程序服务.尽管维杰的回答对我一个月前的思考过程非常有帮助,但我对其中的一部分提出了不同意见.

其他资源

有关应用程序服务的信息非常少.广泛讨论了诸如聚合根,存储库和域服务之类的主题,但是应用服务仅被简要提及或完全省略.

MSDN杂志文章"域驱动设计简介"将应用程序服务描述为将域模型转换和/或公开给外部客户端的方法,例如作为WCF服务.这就是Vijay如何描述应用程序服务.从这个角度来看,应用程序服务是接口.

杰弗里巴勒莫的洋葱架构的文章(部分一个,2和3)是一个很好看的.他将应用程序服务视为应用程序级概念,例如用户会话.虽然这更接近我对应用程序服务的理解,但它仍然不符合我对该主题的看法.

我的想法

我将应用程序服务视为应用程序提供的依赖项.在这种情况下,应用程序可以是桌面应用程序或WCF服务.

是时候了.您从域名开始.此处实现了不依赖于外部资源的所有实体和任何域服务.依赖于外部资源的任何域概念都由接口定义.这是一个可能的解决方案布局(项目名称以粗体显示):

My Solution
- My.Product.Core (My.Product.dll)
  - DomainServices
      IExchangeRateService
    Product
    ProductFactory
    IProductRepository

这些ProductProductFactory类已在核心程序集中实现.这IProductRepository可能是由数据库支持的.实现这不是域的关注,因此由接口定义.

现在,我们将专注于IExchangeRateService.此服务的业务逻辑由外部Web服务实现.但是,它的概念仍然是域的一部分,并由此接口表示.

基础设施

外部依赖项的实现是应用程序基础结构的一部分:

My Solution
+ My.Product.Core (My.Product.dll)
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
  - DomainServices
      XEExchangeRateService
    SqlServerProductRepository

XEExchangeRateServiceIExchangeRateService通过与xe.com通信来实现域服务.通过包含基础结构程序集,您的应用程序可以使用此实现来使用您的域模型.

应用

请注意,我还没有提到应用程序服务.我们现在来看看这些.假设我们想要提供一个IExchangeRateService使用缓存进行快速查找的实现.这个装饰器类的轮廓可能如下所示.

public class CachingExchangeRateService : IExchangeRateService
{
    private IExchangeRateService service;
    private ICache cache;

    public CachingExchangeRateService(IExchangeRateService service, ICache cache)
    {
        this.service = service;
        this.cache = cache;
    }

    // Implementation that utilizes the provided service and cache.
}

注意ICache参数?此概念不属于我们的域,因此它不是域服务.这是一个应用程序服务.它是我们的基础设施的依赖项,可能由应用程序提供.让我们介绍一个演示这个的应用程序:

My Solution
- My.Product.Core (My.Product.dll)
  - DomainServices
      IExchangeRateService
    Product
    ProductFactory
    IProductRepository
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
  - ApplicationServices
      ICache
  - DomainServices
      CachingExchangeRateService
      XEExchangeRateService
    SqlServerProductRepository
- My.Product.WcfService (My.Product.WcfService.dll)
  - ApplicationServices
      MemcachedCache
    IMyWcfService.cs
  + MyWcfService.svc
  + Web.config

这一切都在这样的应用程序中汇集在一起​​:

// Set up all the dependencies and register them in the IoC container.
var service = new XEExchangeRateService();
var cache = new MemcachedCache();
var cachingService = new CachingExchangeRateService(service, cache);

ServiceLocator.For().Use(cachingService);

摘要

完整的应用程序包含三个主要层:

基础设施

应用

域层包含域实体和独立域服务.依赖于外部资源的任何域概念(包括域服务,还包括存储库)都由接口定义.

基础结构层包含域层的接口实现.这些实现可能引入必须为应用程序提供的新的非域依赖性.这些是应用程序服务,由接口表示.

应用程序层包含应用程序服务的实现.如果基础设施层提供的实现不充分,则应用层还可以包含域接口的附加实现.

尽管此透视图可能与服务的常规DDD定义不匹配,但它确实将域与应用程序分开,并允许您在多个应用程序之间共享域(和基础结构)程序集.


我不同意你不同意Vijay的部分,这就是原因.CachingExchangeRateService是一个基础架构问题.即使您通常接受ICache,该ICache的实现依赖于所涉及的技术(即Web,Windows).仅仅因为它的通用性并不能使它成为一种应用服务.应用程序服务是您域的API.如果您想向其他人编写应用程序显示您的域名,他们将使用什么?应用服务,他们可能不需要缓存,所以你的缓存impl对他们没用(即,为什么它的基础设施)
@Tiendq:在传统的分层架构中,基础架构通常与域无关.但在洋葱架构中(参见我的答案中的链接),基础架构实现了域的外部依赖关系.但我不会说基础设施*取决于域名,只是*引用*它.我从洋葱建筑中采用了"基础设施"一词,但"外部"可能是一个更好的名称.
@ dario-g:您必须从请求模型重建/重新填充域模型,并将域模型传递给域服务.[这个问题](http://stackoverflow.com/q/2206005/332100)可能会为您提供一些想法.如果没有,请告诉我,我会看看是否有时间为另一个问题添加答案.

3> Ghola..:

帮助我理解应用服务和域服务之间差异的最佳资源是Eric Evans的货运示例的java实现,可在此处找到.如果您下载它,您可以查看RoutingService(域服务)和BookingService,CargoInspectionService(它们是应用程序服务)的内部.

我的"啊哈"时刻是由两件事引发的:

阅读上面链接中的服务描述,更准确地说是这句话:

域服务以无处不在的语言和域类型表示,即方法参数和返回值是适当的域类.

阅读这篇博文,特别是这部分内容:

我发现在将苹果与橙子分开方面有很大帮助,从应用工作流程的角度思考.有关应用程序工作流的所有逻辑通常最终都是应用程序服务因素,而应用程序服务因素最终构成一个或多个域服务.


GitHub链接到该DDD货物示例:https://github.com/citerus/dddsample-core
我同意,这正是我定义应用服务的方式,它适合我到目前为止遇到的所有情况.域服务处理与域对象相关的所有内容,但这超出了单个实体的范围.例如:BookReferencesService.GetNextAvailableUniqueTrackingNumber(),重点显然是业务规则*.关于应用程序服务,它正是您所描述的,大部分时间我将此业务工作流程放入我的控制器操作中,当我注意到它时,我在应用程序服务层重构此逻辑.我们可以说这个层是用于用例的

4> Timo..:

从红皮书(Vaughn Vernon实施领域驱动设计)中,我就是这样理解的概念:

域对象(实体值对象)封装了(子)域所需的行为,使其自然,富有表现力且易于理解.

域服务封装了不适合单个域对象的此类行为.例如,图书阅览室,妆点BookClient(有相应Inventory的变化)可能会从一个域服务这样做.

应用程序服务处理用例流,包括域之上所需的任何其他问题.它经常通过其API公开此类方法,供外部客户使用.为了构建我们之前的示例,我们的应用程序服务可能会公开一个方法LendBookToClient(Guid bookGuid, Guid clientGuid):

检索Client.

确认其权限.(请注意我们如何保持我们的域模型不受安全/用户管理问题的影响.这种污染可能会导致许多问题.相反,我们在此应用服务中满足此技术要求.)

检索Book.

调用域服务(传递ClientBook)来处理将书借给客户端的实际域逻辑.例如,我认为确认书的可用性肯定是域逻辑的一部分.

应用程序服务通常应该具有非常简单的流程.复杂的应用程序服务流通常表明域逻辑已泄漏出域.

正如您所希望的那样,域模型以这种方式保持非常干净,并且易于理解并与域专家讨论,因为它仅包含其自身的实际业务问题.该应用程序流,而另一方面,是更容易管理,因为它解除域的关注,并成为简洁,明了.


我想说的是,“应用程序服务”也是解决依赖关系的关键。它的方法是一个用例,一个流程,因此它可以针对要使用的具体实现做出明智的决策。数据库事务也适用于此。

5> kboom..:

域服务的扩展.它应该只在域的上下文中看到.这不是一些用户操作,例如关闭帐户或其他东西.域服务适用于没有状态的地方.否则它将是一个域对象.域服务只有在与其他协作者(域对象或其他服务)完成时才会有意义.这使得感觉是另一层的责任.

应用程序服务是初始化和监督域对象和服务之间交互的层.流程通常是这样的:从存储库中获取域对象(或多个对象),执行操作并将其(它们)放回那里(或不).它可以做更多 - 例如,它可以检查域对象是否存在,并相应地抛出异常.因此,它允许用户与应用程序交互(这可能是其名称的起源) - 通过操作域对象和服务.应用程序服务通常应代表所有可能的用例.在考虑域之前,您可以做的最好的事情是创建应用程序服务接口,这将使您更好地了解您真正想要做的事情.拥有这些知识使您可以专注于域.

一般来说,存储库可以注入域服务,但这种情况相当罕见.虽然应用层大多数时间都是这样做的.


"域服务适用于没有状态的地方.否则它将成为域对象." 让它为我点击.谢谢.

6> GorkemHalulu..:

域服务:域服务中包含不真正适合单个实体或需要访问存储库的方法.域服务层还可以包含其自己的域逻辑,并且作为实体和值对象的域模型的一部分.

应用程序服务:应用程序服务是位于域模型上方并协调应用程序活动的薄层.它不包含业务逻辑,也不包含任何实体的状态; 但是,它可以存储业务工作流事务的状态.您使用Application服务使用Request-Reply消息传递模式将API提供到域模型中.

Millett,C(2010).专业的ASP.NET设计模式.威利出版社.92.

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有