领域驱动设计中的服务!!
服务是域模型的一级公民。当模型的概念扭曲了任何实体或值对象时,服务是合适的。从埃文斯的DDD,一个好的服务有这些特点:
操作涉及到一个领域概念,它不是实体或值对象的自然组成部分
接口是由领域模型中的其他元素来定义
操作是无状态的
服务总是以接口的形式公开,不是“可切换性”、可测试性或类似的接口,而是以契约的形式公开一组内聚的操作。这里我强调一下,当人们说仅有一个实现类的接口是一种不好的设计气味时,它总是让我烦恼。不,接口是用来公开契约的。接口传达了设计意图,比一个类要好得多。
但我看到的大多数服务示例都是一些琐碎的事情,如IEmailSender。但在DDD分层架构的大多数层中都存在服务:
Application
Domain
Infrastructure
基础设施服务类似于IEmailSender,它直接与外部资源(如文件系统、注册表、SMTP、数据库等)进行通信,NHibernate之类的东西将在基础设施中出现。
领域服务是协调器,允许在许多不同的小部件之间实现更高级别的功能。这些包括OrderProcessor,ProductFinder,FundsTransferService,等等。由于领域服务是领域模型的一级公民,因此它们的名称和用法应该是通用语言的一部分。意义和责任应该对利益相关者或领域专家有意义。
在很多情况下,我们所写的软件正在取代或补充一个人的工作,比如Order Processor(订单处理器),所以我们经常在现有的业务流程中找到名字和责任的灵感。如果一个现有的名称不合适,我们就会深入到这个领域,尝试与领域专家(可能已经存在但没有名称)的隐藏概念。
最后,我们有应用服务。在许多情况下,应用服务是外部世界使用的接口,外部世界无法通过我们的实体对象进行通信,但可能还有其他的表示方式。应用服务可以将外部消息映射到内部操作和流程,与领域和基础设施层中的服务进行通信,从而为外部客户提供有凝聚力的操作。消息传递模式倾向于规则化应用服务,因为其他的服务层(即领域服务和基础设施服务,毕竟这二者是这这一层之下的,所以其没有办法做反向的引用)没有对应用程序服务的引用。业务规则是不允许出现在应用服务层中的,因为这些规则属于域层。
在自顶而下的设计中,我们通常从应用层或者领域层开始,定义实际提供给客户端使用的接口,然后使用TDD(测试驱动)来驱动实现。由于我们总是从客户端角度出发,使用实际的客户端场景,我们有高度的信心,我们正在构建的东西将创造成功并增加价值。当故事是垂直的功能切片时,这是相当简单的,至少是机械的。
我过去常常错误地认为服务是一种无可避免的灾祸,仅限于基础设施层。通过我们最近的Austin DDD Book Club,通过更多的阅读和对话,我开始意识到应用程序和领域服务在创建一个设计良好的模型方面的潜力。