DDD领域驱动设计:四层架构应用

Posted 、Dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DDD领域驱动设计:四层架构应用相关的知识,希望对你有一定的参考价值。


前言

分层架构是运用最为广泛的一种架构模式,几乎每个软件系统都需要通过分层来隔离不同的关注点,以应对不同需求的变化,并且使得这种变化可以独立进行。 对于分层架构来说,层次越往上其抽象层次就越面向业务和用户,层次越往下其抽象层次就越面向技术和设备。

一、DDD四层与传统三层区别

我们常用的三层架构模型划分为表现层,业务逻辑层,数据访问层等,在DDD分层结构中既有联系又有区别,个人认为主要有如下异同:

在架构设计上,在DDD分层结构中将传统三层架构的业务逻辑层拆解为应用层和领域层
其中Application划分为很薄的一层服务,非核心的逻辑放到此层去实现,核心的业务逻辑表现下沉到领域层去实现,凝练为更为精确的业务规则集合,通过领域对象去阐述说明。

在建模方式上,DDD分层的建模思维方式有别于传统三层
传统三层通常是以数据库为起点进行数据库分析设计,而DDD则需要以业务领域模型为核心建模(即面向对象建模方式),更能体现对现实世界的抽象。
故在DDD分层凸显领域层的重要作用,领域层为系统的核心,包括所有的业务领域模型的抽象表达。

在职责划分上,基础设施层涵盖了2方面内容:
持久化功能,其中原三层架构的数据访问层下沉到基础设施层的持久化机制实现
通用技术支持,一些公共通用技术支持也放到基础设施层去实现。


二、四层架构详解

1.分层作用

分层英文描述
表现层User Interface用户界面层,或者表现层,负责向用户显示解释用户命令
应用层Application Layer定义软件要完成的任务,并且指挥协调领域对象进行不同的操作。该层不包含业务领域知识。
领域层Domain Layer也可称为模型层,系统的核心,负责表达业务概念,业务状态信息以及业务规则。即包含了该领域(问题域)所有复杂的业务知识抽象和规则定义。该层主要精力要放在领域对象分析上,可以从实体,值对象,聚合(聚合根),领域服务,领域事件,仓储,工厂等方面入手
基础设施层Infrastructure Layer主要有2方面内容,一是为领域模型提供持久化机制,当软件需要持久化能力时候才需要进行规划;一是对其他层提供通用的技术支持能力,如消息通信,通用工具,配置等的实现;

2.领域对象

类型英文描述
值对象value object无唯一标识的简单对象
实体entity充血的领域模型,有唯一标识
聚合(聚合根)aggregate实体的聚合,拥有聚合根,可为某一个实体
领域服务service无法归类到某个具体领域模型的行为
领域事件event不常用
仓储repository持久化相关,与基础设施层关联
工厂factory负责复杂对象创建
模块module子模块引入,可以理解为子域划分

三、编码实践

1.代码结构

├─com.company.microservice
│    │ 
│    ├─apis   API接口层
│    │    ├─model     视图模型,数据模型定义 vo/dto(大多数情況是一样的)
│    │    ├─assembler    装配器,实现模型转换eg. apiModel<=> domainModel
│    │    └─controller   控制器,对外提供(Restful)接口
│    │ 
│    ├─application   应用层
│    │    ├─service  应用服务,非核心服务
│    │    ├─task     任务定义,协调领域模型 
│    │    └─***      others
│    │ 
│    ├─domain   领域层
│    │    ├─common       公共代码抽取,限于领域层有效 
│    │    ├─events       领域事件
│    │    ├─model        领域模型 
│    │    │    ├─dict    领域划分的模块,可理解为子域划分
│    │    │    │    ├─DictVo.java       领域值对象
│    │    │    │    ├─DictEntity.java   领域实体,充血的领域模型,如本身的CRUD操作在此处
│    │    │    │    ├─DictAgg.java      领域聚合,通常表现为实体的聚合,需要有聚合根
│    │    │    │    └─DictService.java  领域服务,不能归与上述模型,如分页条件查询等可写在此处
│    │    │    ├─xxx
│    │    │    │    ├─xxxEntity.java         
│    │    │    │    ├─bbbAgg.java     
│    │    │    │    └─cccAgg.java        
│    │    ├─service      领域服务类,一些不能归属某个具体领域模型的行为
│    │    └─factory      工厂类,负责复杂领域对象创建,封装细节 
│    │ 
│    ├─infrastructure  基础设施层
│    │    ├─persistent   持久化机制
│    │    │    ├─po           持久化对象 
│    │    │    └─repository   仓储类,持久化接口&实现,可与ORM映射框架结合
│    │    ├─general      通用技术支持,向其他层输出通用服务
│    │    │    ├─config       配置类
│    │    │    ├─toolkit      工具类  
│    │    │    └─common       基础公共模块等
│    │ 
│    └─resources  
│        ├─statics  静态资源
│        ├─template 系统页面 
│        └─application.yml   全局配置文件


四、常见问题

1.领域模型(充血模型)注入问题

区别于传统的分层后,在domain中更多关注业务逻辑,考虑到要与spring框架集成,需要注意一个领域模型中注入的问题

在传统分层中,controller,service,repo均注册为spring管理的bean,但是在domain层中,service一部分的业务逻辑划分到了具体的领域对象中去实现了,显然这些对象却不能注册为单例bean,因此在此处不能沿用与原来分层结构中service层中通过@Autowired or @Resource等注入接口

关于这个问题,此处建议使用ApplicationContext实现

即通过一个工具类 ApplicationContextUtils 实现 ApplicationContextAware获取bean的方法,即 getBean()方法,然后我们就可以在我们的领域模型中直接应用该工具类来获取Spring托管的singleton对象,xxxRepo=ApplicationContextUtils.getBean(“xxxRepository”)


结尾

  • 感谢大家的耐心阅读,如有建议请私信或评论留言。
  • 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步

以上是关于DDD领域驱动设计:四层架构应用的主要内容,如果未能解决你的问题,请参考以下文章

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

DDD-领域驱动设计重构的痛点及项目结构的划分

领域驱动设计 领域事件DDD分层架构

React DDD 领域驱动架构设计

打通架构与业务 领域驱动设计(DDD)加速企业产品持续演进

DDD领域驱动设计-DDD概览