领域驱动设计(DDD)分层架构的三种模式

模式一:四层架构 1 User Interface为用户界面层(或表示层),负责向用户显示信息和解释用户命令。这里指的用户可以是另一个计算机系统,不一定是使用

模式一:四层架构

1.User Interface为用户界面层(或表示层),负责向用户显示信息和解释用户命令。这里指的用户可以是另一个计算机系统,不一定是使用用户界面的人。
2.Application为应用层,定义软件要完成的任务,并且指挥表达领域概念的对象来解决问题。这一层所负责的工作对业务来说意义重大,也是与其它系统的应用层进行交互的必要渠道。应用层要尽量简单,不包含业务规则或者知识,而只为下一层中的领域对象协调任务,分配工作,使它们互相协作。它没有反映业务情况的状态,但是却可以具有另外一种状态,为用户或程序显示某个任务的进度。
3.Domain为领域层(或模型层),负责表达业务概念,业务状态信息以及业务规则。尽管保存业务状态的技术细节是由基础设施层实现的,但是反映业务情况的状态是由本层控制并且使用的。领域层是业务软件的核心,领域模型位于这一层。
4.Infrastructure层为基础实施层,向其他层提供通用的技术能力:为应用层传递消息,为领域层提供持久化机制,为用户界面层绘制屏幕组件,等等。基础设施层还能够通过架构框架来支持四个层次间的交互模式。

模式二:五层架构

一、三层架构(Data、Context和Interactive)
Data层描述系统有哪些领域概念及其之间的关系,该层专注于领域对象的确立和这些对象的生命周期管理及关系,让程序员站在对象的角度思考系统,从而让“系统是什么”更容易被理解。
Context层:是尽可能薄的一层。Context往往被实现得无状态,只是找到合适的role,让role交互起来完成业务逻辑即可。但是简单并不代表不重要,显示化context层正是为人去理解软件业务流程提供切入点和主线。
Interactive层主要体现在对role的建模,role是每个context中复杂的业务逻辑的真正执行者,体现“系统做什么”。role所做的是对行为进行建模,它联接了context和领域对象。由于系统的行为是复杂且多变的,role使得系统将稳定的领域模型层和多变的系统行为层进行了分离,由role专注于对系统行为进行建模。该层往往关注于系统的可扩展性,更加贴近于软件工程实践,在面向对象中更多的是以类的视角进行思考设计。
二、五层架构
1.User Interface是用户接口层,主要用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给Application层的接口。
2.Application层是应用层,负责多进程管理及调度、多线程管理及调度、多协程调度和维护业务实例的状态模型。当调度层收到用户接口层的请求后,委托Context层与本次业务相关的上下文进行处理。
3.Context是环境层,以上下文为单位,将Domain层的领域对象cast成合适的role,让role交互起来完成业务逻辑。
4.Domain层是领域层,定义领域模型,不仅包括领域对象及其之间关系的建模,还包括对象的角色role的显式建模。
5.Infrastructure层是基础实施层,为其他层提供通用的技术能力:业务平台,编程框架,持久化机制,消息机制,第三方库的封装,通用算法,等等。
三、六层架构
1.User Interface是用户接口层,主要用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给Scheduler层的接口。
2.Scheduler是调度层,负责多进程管理及调度、多线程管理及调度、多协程调度和维护业务实例的状态模型。当调度层收到用户接口层的请求后,委托Transaction层与本次操作相关的事务进行处理。
3.Transaction是事务层,对应一个业务流程,比如UE Attach,将多个同步消息或异步消息的处理序列组合成一个事务,而且在大多场景下,都有选择结构。万一事务执行失败,则立即进行回滚。当事务层收到调度层的请求后,委托Context层的Action进行处理,常常还伴随使用Context层的Specification(谓词)进行Action的选择。
4.Context是环境层,以Action为单位,处理一条同步消息或异步消息,将Domain层的领域对象cast成合适的role,让role交互起来完成业务逻辑。环境层通常也包括Specification的实现,即通过Domain层的知识去完成一个条件判断。
5.Domain层是领域层,定义领域模型,不仅包括领域对象及其之间关系的建模,还包括对象的角色role的显式建模。
6.Infrastructure层是基础实施层,为其他层提供通用的技术能力:业务平台,编程框架,持久化机制,消息机制,第三方库的封装,通用算法,等等。

模式三:六边形架构

有一种方法可以改进分层架构,即依赖倒置原则(Dependency Inversion Principle, DIP),它通过改变不同层之间的依赖关系达到改进目的。
根据该定义,DDD分层架构中的低层组件应该依赖于高层组件提供的接口,即无论高层还是低层都依赖于抽象,整个分层架构好像被推平了。如果我们把分层架构推平,再向其中加入一些对称性,就会出现一种具有对称性特征的架构风格,即六边形架构。六边形架构是Alistair Cockburn在2005年提出的,在这种架构中,不同的客户通过“平等”的方式与系统交互。需要新的客户吗?不是问题。只需要添加一个新的适配器将客户输入转化成能被系统API所理解的参数就行。同时,对于每种特定的输出,都有一个新建的适配器负责完成相应的转化功能。

六边形架构也称为端口与适配器,如下图所示:
在这里插入图片描述

六边形每条不同的边代表了不同类型的端口,端口要么处理输入,要么处理输出。对于每种外界类型,都有一个适配器与之对应,外界通过应用层API与内部进行交互。上图中有3个客户请求均抵达相同的输入端口(适配器A、B和C),另一个客户请求使用了适配器D。假设前3个请求使用了HTTP协议(浏览器、REST和SOAP等),而后一个请求使用了AMQP协议(比如RabbitMQ)。端口并没有明确的定义,它是一个非常灵活的概念。无论采用哪种方式对端口进行划分,当客户请求到达时,都应该有相应的适配器对输入进行转化,然后端口将调用应用程序的某个操作或者向应用程序发送一个事件,控制权由此交给内部区域。
应用程序通过公共API接收客户请求,使用领域模型来处理请求。我们可以将DDD战术设计的建模元素Repository(存储库)的实现看作是持久化适配器,该适配器用于访问先前存储的聚合实例或者保存新的聚合实例。正如图中的适配器E、F和G所展示的,我们可以通过不同的方式实现资源库,比如关系型数据库、基于文档的存储、分布式缓存或内存存储等。如果应用程序向外界发送领域事件消息,我们将使用适配器H进行处理。该适配器处理消息输出,而上面提到的处理AMQP消息的适配器则是处理消息输入的,因此应该使用不同的端口。
我们在实际的项目开发中,不同层的组件可以同时开发。当一个组件的功能明确后,就可以立即启动开发。由于该组件的用户有多个,并且这些用户的侧重点不同,所以需要提供多个不同的接口。同时,这些用户的认识也是不断深入的,可能会多次重构相关的接口。于是,组件的多个用户经常会找组件的开发者讨论这些问题,无形中降低了组件的开发效率。
我们换一种方式,组件的开发者在明确了组件的功能后就专注于功能的开发,确保功能稳定和高效。组件的用户自己定义组件的接口(端口),然后基于接口写测试,并不断演进接口。在跨层集成测试时,由组件开发者或用户再开发一个适配器就可以了。