ddd领域驱动设计三种实现_产品架构

2022-11-15 11:02:56 浏览数 (1)

文章目录

  • 前言
  • 一、DDD四层与传统三层区别
  • 二、四层架构详解
    • 1.分层作用
    • 2.领域对象
  • 三、编码实践
    • 1.代码结构
  • 四、常见问题
    • 1.领域模型(充血模型)注入问题
  • 结尾

前言

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


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

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

在架构设计上,在DDD分层结构中将传统三层架构的业务逻辑层拆解为应用层和领域层

其中Application划分为很薄的一层服务,非核心的逻辑放到此层去实现,核心的业务逻辑表现下沉到领域层去实现,凝练为更为精确的业务规则集合,通过领域对象去阐述说明。

在建模方式上,DDD分层的建模思维方式有别于传统三层:

传统三层通常是以数据库为起点进行数据库分析设计,而DDD则需要以业务领域模型为核心建模(即面向对象建模方式),更能体现对现实世界的抽象。

故在DDD分层凸显领域层的重要作用,领域层为系统的核心,包括所有的业务领域模型的抽象表达。

在职责划分上,基础设施层涵盖两方面内容:

持久化功能,其中原三层架构的数据访问层下沉到基础设施层的持久化机制实现

通用技术支持,一些公共通用技术支持也放到基础设施层去实现。


二、四层架构详解

1.分层作用

分层

英文

描述

表现层

User Interface

用户界面层,或者表现层,负责向用户显示解释用户命令

应用层

Application Layer

定义软件要完成的任务,并且指挥协调领域对象进行不同的操作。该层不包含业务领域知识。

领域层

Domain Layer

也可称为模型层,系统的核心,负责表达业务概念,业务状态信息以及业务规则。即包含了该领域(问题域)所有复杂的业务知识抽象和规则定义。该层主要精力要放在领域对象分析上,可以从实体,值对象,聚合(聚合根),领域服务,领域事件,仓储,工厂等方面入手

基础设施层

Infrastructure Layer

主要有2方面内容,一是为领域模型提供持久化机制,当软件需要持久化能力时候才需要进行规划;一是对其他层提供通用的技术支持能力,如消息通信,通用工具,配置等的实现;

2.领域对象

类型

英文

描述

值对象

value object

无唯一标识的简单对象

实体

entity

充血的领域模型,有唯一标识

聚合(聚合根)

aggregate

实体的聚合,拥有聚合根,可为某一个实体

领域服务

service

无法归类到某个具体领域模型的行为

领域事件

event

不常用

仓储

repository

持久化相关,与基础设施层关联

工厂

factory

负责复杂对象创建

模块

module

子模块引入,可以理解为子域划分


三、编码实践

1.代码结构

代码语言:javascript复制
├─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”)


结尾

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/234992.html原文链接:https://javaforall.cn

0 人点赞