应用层,通常是用户接口层的直接使用者 。
但是在应用层中并不实现真正的业务规则,而是根据实际的 use case 来协调领域层提供的能力,也可以说,应用层主要做的是编排工作 。
另外,应用层还负责了事务这个比较重要的功能 。
3、领域层
领域层是整个业务的核心层 。我们一般会使用充血模型来建模实际的领域对象 。
同时,由于业务的核心价值在于其运作模式,而不是具体的技术手段或实现方式 。因此,领域层的编码原则上不允许依赖其他外部对象 。
4、基础设施层
基础设施层,是在技术上具体的实现细节,它为上面各层提供通用的技术能力 。
比如我们使用了哪种数据库,数据是怎么存储的,有没有用到缓存、消息队列等,都是在这一层要实现的 。
对于这四个层次的划分,大家通常都没有太多的异议 。但是在层与层之间的依赖关系上,后续又衍生出了很多的改良版本 。比如在 IDDD 一书中,就给出了下图所示的分层架构:

文章插图
这里最大的不同,就是将领域层放到了整个架构的最下面,也即领域层之下就不再有任何的其他依赖 。这么做是没有问题的,但是最上面的基础设施层看起来却怪怪的 。
【DDD 中关于应用架构的那些事】在实际开发中,领域层的领域服务往往需要访问持久化组件,以及基础设施层中的其他组件,而对于持久化组件来说,不可避免地需要依赖领域层的实体对象 。如此一来,领域层和基础设施层,就产生了双向依赖关系 。
实际的解决方式,就是让领域层和基础设施层 都依赖一个统一的抽象,比如对于模型的持久化有 Repository 接口,对其他外部资源的访问也可以通过接口的形式来解耦合 。但是 Repository 接口跟其他接口 又有些不太一样,Repository 因为需要参与到实体的整个生命周期中,所以在很多时候 Repository 都被看作是领域层中的一员 。而对基础设施层中其他组件的抽象,是不适合定义到领域层的 。
?? DDD代码模型
结合上面的描述,这个时候再来看代码的组织形式,就比较清晰了 。默认情况下,一个上下文对应了一个服务,我们这里以包含单个上下文的情况为例,给出如下的代码目录结构:

文章插图
对上面的代码结构做一个简短的说明:
• Application,对应到架构里的应用层,其内可能包含一些 assembler 和 DTO,assembler 主要用于将领域对象转换成返回需要的数据格式,这些数据格式以DTO的形式进行定义,这些DTO没有任何的业务逻辑,就是单纯的数据对象 。
• domAIn,对应的是领域层,仓储的接口也是放在这一层的 。
• handler,对应的是架构里的用户接口层,但其本质上还是属于基础设施层的一部分,这里单独提出来也仅仅是为了凸显它的重要性 。在这一层,只可以直接访问应用层 。
• infra,对应的是基础设施层,根据对不同资源的继承需求,可以在 infra 下继续分包 。
• interfaces,是对基础设施层中除持久化以外的中间件的抽象,也即我们在这里定义访问中间件的接口,具体的实现还是放在基础设施层 。这里将接口单独放到一个包中,为的是避免在领域层与应用层对基础设施层的直接依赖,如此就通过依赖反转解耦了具体的技术细节 。
至此,我们就明确了代码的分层组织结构,以及彼此之间的依赖关系 。
我们在文章开头提到的第二个问题是上下文的集成,在实际工作中,相信大家都会使用到微服务,这样一来,如何集成就成为我们必须要考虑的问题 。
02? 与其他上下文集成
上下文的集成无外乎两种方式,一种是通过RPC进行集成,另一种是通过领域事件进行集成 。
通过领域事件集成,也就是领域事件的发送和消费,这个我们在前面的文章中已经做了比较详细的介绍,这里不再赘述 。
接下来主要说说通过 RPC 进行集成 。
?? 开放主机与发布语言
我们先来看一个在 DDD 中,经常用来表示集成方式的示例图:

文章插图
其中,被集成方(A上下文,U 是 Upstream 的缩写)采用了开放主机和发布语言的方式,而集成方(B上下文,D 是 Downstream 的缩写)则使用了防腐层 。几个缩写的含义如下:
• OHS(Open Host Service):开放主机服务,即定义一种协议,子系统可以通过该协议来访问你的服务 。
推荐阅读
- 显示器有曲面和直面之分,你知道其中的区别吗?
- 电脑硬盘如何分区更好?关于硬盘分区的小窍门
- NAT 如何在 Linux 中进行网络地址转换
- 腾讯联手育碧打造!中国主题《刺客信条:代号JADE》即将有大爆料
- 王者荣耀中天克盾山的英雄有哪些?
- 5个喝水误区,你中了几条?
- “量子”到底是什么?为什么量子力学中,上帝要掷骰子?
- 银元|五版100元纸币中的,稀有冠号有哪些?
- 福建中医药大学图书馆官网~福建中医药大学就读体验
- 吴启华|港星吴启华在富婆家中庆生,整桌茅台好阔气,和美女合影紧张搓手
