解决怎样保证代码与模型一致的问题,这个问题又分成两个层面
- 第一个层面是要有一个合理的代码架构
- 第二个层面是更详细的代码编写
分层架构的圈层结构图
分层架构把代码分成若干层,每层负责不同的关注点。 图里的箭头表示依赖关系,这里的意思是只能外层依赖内层,内层不能依赖外层。
这背后其实是根据软件架构中的一个重要原则:代码中不稳定的部分,应该依赖稳定的部分。所以,分层架构中越是内层,就越稳定,越是外层,相对就越容易变化。
分离领域
DDD 对代码架构最核心的要求就是要将领域层分离出来
领域层示意图
给领域一个“门面”
领域层封装的逻辑通常是细粒度的,并不适合直接作为 API 暴露给外部。另外,还有一些不属于领域层的横切关注点,比如像事务控制,应该单独处理。 所以,我们往往要在领域层外面再加一层,DDD 和六边形架构都将这一层称为 Application,也就是应用层。
领域 + 应用层示意图
Application 层主要负责的逻辑
接受来自客户端的请求,调用和协调领域层的逻辑来解决问题;
将领域层的处理结果封装为更简单的粗粒度对象,作为对外 API 的参数。这里说的粗粒度对象一般是 DTO(Data Transfer Object),也就是没有逻辑的数据传输对象,应用层负责 DTO 和领域对象的数据转换;
负责处理事务、日志、权限等等横切关注点。从设计模式的角度,这一层相当于“门面”(Facade)模式,如果你想更深入地了解这个模式,可以读一下相关书籍,例如 《Head First 设计模式》。
应用层本身并不包含领域逻辑,而是对领域层中的逻辑进行封装和编排。我们不妨把应用层的逻辑称为应用逻辑。
封装应用逻辑的类通常没有状态,只有方法,一般称为应用服务,我们可以用 XxxService 的形式来命名。
Adapter 层处理输入输出
这一层的目的是把业务功能“适配”到不同的输入输出技术。
适配器会把和具体技术有关的请求,翻译成和技术无关的请求,再调用应用层来实现业务功能;在接收到应用层的返回值以后,又转化成技术相关的响应,返回给外界。 也就是说适配器层屏蔽了输入输出技术的差异,从而使应用层与具体技术无关,这样就达到了分离关注点的目的。
在六边形架构里,把由外向内的适配器叫做 driving adapter,我把它译作主动适配器;而由内向外的适配器叫做 driven adapter,可以译作被动适配器。
准确地说,被动适配器的作用不限于访问数据库,而是访问所有外部资源。
这里的 Adapter 感觉就是 Anticorruption Layer(防腐层)
用“适配器”处理数据持久化
主动适配器 | 被动适配器 | |
---|---|---|
英文名 | Driving Adapter | Driven Adapter |
定义描述 | 由外向内调用 | 由内向外调用 |
组件举例 | Controller | Repository(仓库) |
场景举例 | HTTP 客户端调用系统 | 系统调用数据库 |
common 层存放通用工具和框架
通用工具、对 Spring 框架进行的封装、自己的小框架,这些框架性的代码可能用于上面说的任何一层。
虽然这些代码可能被前面的所有层依赖,但它和上面说的各层不在同一个纬度。
它们是对各层代码起到公共的支撑作用的
common 包下两个子包的说明
- framework 存放框架性的代码
- util 存放工具性的代码
框架和工具的一般区别
- 框架会调用我们自己写的代码
- 工具则被我们写的代码所调用