第7章 领域服务
- 第1章 DDD入门
- 第2章 领域、子域和限界上下文
- 第3章 上下文映射图
- 第4章 架构
- 第5章 实体
- 第6章 值对象
- 第7章 领域服务
- 第8章 领域事件
- 第9章 模块
- 第10章 聚合
- 第11章 工厂
- 第12章 资源库
- 第13章 集成限界上下文
- 第14章 应用程序
本章学习路线图
- 学习如何在领域模型中使用领域服务
- 学习什么时领域服务
- 学习何时应该使用领域服务
- 从SaaSOvation项目的两个例子中学习如何对领域服务进行建模
领域中的服务表示一个无状态的操作,它用于实现特定于某个领域的任务。当某个操作不适合放在**聚合(10)**和值对象(6)上时,最好的方式便是使用领域服务了。
什么是领域服务
当领域中的某个操作过程或转换过程不是实体或者值对象的职责时,我们应该将该操作放在一个单独的接口中,即领域服务。请确保该领域服务和通用语言是一致的;并且保证它是无状态的;并且能够明确地表达限界上下文中的通用语言(1)。通常来说,领域模型主要关注于某个特定于某个领域的业务,同样,领域服务也具有相似的特点。
- 执行一个显著的业务操作过程
- 对领域对象进行转换
- 以多个领域对象作为输入进行计算,结果产生一个值对象
需要明确最后一点,这是领域服务很常见的应用场景,它可能需要多个聚合作为输入。
请不要将领域服务和应用服务混杂在一起。在应用服务中并不会处理业务逻辑,但是领域服务恰恰是处理业务逻辑的。简单来讲应用服务是领域模型的客户方,进而也是领域服务的客户方。
例如通过RPC、MoM实现的SOA服务等这些远程客户端与某个业务系统交互的场景,都不是领域服务。
请确定你是否需要一个领域服务
请不要倾向于将一个领域概念建模成领域服务,而是只有在有必要的时候才这么做。过度地使用领域服务将导致贫血领域模型,即所有的业务逻辑都位于领域服务中。
书中以“系统必须对User认证,并且只有当Tenant处于激活状态时才能对User进行认证”为例,逐步给出使用领域服务要优于将认证操作放在实体中。
UserDescriptor userDescriptor = DomainRegistry
.authenticationService()
.authentication(aTenantId, aUsername, aPassword);
最终使用上述方式,将所有的认证细节放在领域服务中,而不是应用服务。在需要的情况下,领域服务可以使用任何领域对象来完成操作,包括对密码进行加密。客户端不需要知道任何认证细节。
建模领域服务
本章节以前一章节中用户认证服务为线索,给出了具体的实现过程,并给出了充分的解释以及这种方法的好处(如解耦、扩展和依赖注入),建议结合书中代码阅读。
测试领域服务
我们希望那个从客户端的角度对领域服务进行建模,同时我们也希望测试能够反映出领域服务的使用方式。
书中对上一章节认证服务的实现进行充分测试,建议结合书中代码阅读。