有人可以通过提供一些示例来解释域和应用程序服务之间的区别吗?并且,如果服务是域服务,我是否会将此服务的实际实现放在域程序集中?如果是,我是否也会将存储库注入该域服务?一些信息会非常有用.
服务有三种形式:域服务,应用服务和基础设施服务.
域服务:封装 不自然地适合域对象的业务逻辑,并且不是典型的CRUD操作 - 那些属于存储库.
应用程序服务:由外部使用者用于与您的系统通信(想想Web服务).如果消费者需要访问CRUD操作,他们就会在这里公开.
基础设施服务:用于抽象技术问题(例如MSMQ,电子邮件提供商等).
保持域服务和域对象是明智的 - 它们都专注于域逻辑.是的,您可以将存储库注入您的服务.
Application Services通常使用域服务和存储库来处理外部请求.
希望有所帮助!
(如果你不想阅读,底部有一个摘要:-)
我也一直在努力精确定义应用程序服务.尽管维杰的回答对我一个月前的思考过程非常有帮助,但我对其中的一部分提出了不同意见.
有关应用程序服务的信息非常少.广泛讨论了诸如聚合根,存储库和域服务之类的主题,但是应用服务仅被简要提及或完全省略.
MSDN杂志文章"域驱动设计简介"将应用程序服务描述为将域模型转换和/或公开给外部客户端的方法,例如作为WCF服务.这就是Vijay如何描述应用程序服务.从这个角度来看,应用程序服务是域的接口.
杰弗里巴勒莫的洋葱架构的文章(部分一个,2和3)是一个很好看的.他将应用程序服务视为应用程序级概念,例如用户会话.虽然这更接近我对应用程序服务的理解,但它仍然不符合我对该主题的看法.
我将应用程序服务视为应用程序提供的依赖项.在这种情况下,应用程序可以是桌面应用程序或WCF服务.
是时候了.您从域名开始.此处实现了不依赖于外部资源的所有实体和任何域服务.依赖于外部资源的任何域概念都由接口定义.这是一个可能的解决方案布局(项目名称以粗体显示):
My Solution - My.Product.Core (My.Product.dll) - DomainServices IExchangeRateService Product ProductFactory IProductRepository
这些Product
和ProductFactory
类已在核心程序集中实现.这IProductRepository
可能是由数据库支持的.实现这不是域的关注,因此由接口定义.
现在,我们将专注于IExchangeRateService
.此服务的业务逻辑由外部Web服务实现.但是,它的概念仍然是域的一部分,并由此接口表示.
外部依赖项的实现是应用程序基础结构的一部分:
My Solution + My.Product.Core (My.Product.dll) - My.Product.Infrastructure (My.Product.Infrastructure.dll) - DomainServices XEExchangeRateService SqlServerProductRepository
XEExchangeRateService
IExchangeRateService
通过与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定义不匹配,但它确实将域与应用程序分开,并允许您在多个应用程序之间共享域(和基础结构)程序集.
帮助我理解应用服务和域服务之间差异的最佳资源是Eric Evans的货运示例的java实现,可在此处找到.如果您下载它,您可以查看RoutingService(域服务)和BookingService,CargoInspectionService(它们是应用程序服务)的内部.
我的"啊哈"时刻是由两件事引发的:
阅读上面链接中的服务描述,更准确地说是这句话:
域服务以无处不在的语言和域类型表示,即方法参数和返回值是适当的域类.
阅读这篇博文,特别是这部分内容:
我发现在将苹果与橙子分开方面有很大帮助,从应用工作流程的角度思考.有关应用程序工作流的所有逻辑通常最终都是应用程序服务因素,而应用程序服务因素最终构成一个或多个域服务.
从红皮书(Vaughn Vernon实施领域驱动设计)中,我就是这样理解的概念:
域对象(实体和值对象)封装了(子)域所需的行为,使其自然,富有表现力且易于理解.
域服务封装了不适合单个域对象的此类行为.例如,图书阅览室,妆点Book
到Client
(有相应Inventory
的变化)可能会从一个域服务这样做.
应用程序服务处理用例流,包括域之上所需的任何其他问题.它经常通过其API公开此类方法,供外部客户使用.为了构建我们之前的示例,我们的应用程序服务可能会公开一个方法LendBookToClient(Guid bookGuid, Guid clientGuid)
:
检索Client
.
确认其权限.(请注意我们如何保持我们的域模型不受安全/用户管理问题的影响.这种污染可能会导致许多问题.相反,我们在此应用服务中满足此技术要求.)
检索Book
.
调用域服务(传递Client
和Book
)来处理将书借给客户端的实际域逻辑.例如,我认为确认书的可用性肯定是域逻辑的一部分.
应用程序服务通常应该具有非常简单的流程.复杂的应用程序服务流通常表明域逻辑已泄漏出域.
正如您所希望的那样,域模型以这种方式保持非常干净,并且易于理解并与域专家讨论,因为它仅包含其自身的实际业务问题.该应用程序流,而另一方面,是也更容易管理,因为它解除域的关注,并成为简洁,明了.
域服务是域的扩展.它应该只在域的上下文中看到.这不是一些用户操作,例如关闭帐户或其他东西.域服务适用于没有状态的地方.否则它将是一个域对象.域服务只有在与其他协作者(域对象或其他服务)完成时才会有意义.这使得感觉是另一层的责任.
应用程序服务是初始化和监督域对象和服务之间交互的层.流程通常是这样的:从存储库中获取域对象(或多个对象),执行操作并将其(它们)放回那里(或不).它可以做更多 - 例如,它可以检查域对象是否存在,并相应地抛出异常.因此,它允许用户与应用程序交互(这可能是其名称的起源) - 通过操作域对象和服务.应用程序服务通常应代表所有可能的用例.在考虑域之前,您可以做的最好的事情是创建应用程序服务接口,这将使您更好地了解您真正想要做的事情.拥有这些知识使您可以专注于域.
一般来说,存储库可以注入域服务,但这种情况相当罕见.虽然应用层大多数时间都是这样做的.
域服务:域服务中包含不真正适合单个实体或需要访问存储库的方法.域服务层还可以包含其自己的域逻辑,并且作为实体和值对象的域模型的一部分.
应用程序服务:应用程序服务是位于域模型上方并协调应用程序活动的薄层.它不包含业务逻辑,也不包含任何实体的状态; 但是,它可以存储业务工作流事务的状态.您使用Application服务使用Request-Reply消息传递模式将API提供到域模型中.
Millett,C(2010).专业的ASP.NET设计模式.威利出版社.92.