DDD领域驱动设计基础

news2024/11/27 4:21:35

什么领域驱动模型

领域驱动模型一种设计思想,我们又称为DDD设计思想。是一种为了解决传统设计思想带来的维护困难,沟通困难和交互困难而产生的一种新的思想。

架构模式的演进

单体架构

采用面向对象的设计方法,系统包括业务接入层、业务逻辑层和数据库层,采用经典的三层架构。
这种架构的问题:

  • 贫血模型:只起到数据类的作用,业务逻辑散落到 service,可维护性越来越差
  • service 类承接的所有的业务逻辑,越来越臃肿,很容易出现几千行的 service 类
  • 对外接口直接暴露实体模型,导致不必要开放内部逻辑对外暴露,就算有 DTO 类一般也是实体类的直接 copy
  • 外部依赖层直接从 service 层调用,字段转换、异常处理大量充斥在 service 方法中

这种架构容易使系统变得臃肿,可扩展性和弹性伸缩性差

  • 贫血模型:只有get、set方法,所有的业务逻辑都不包含在内,而是放在service中
  • 充血模型:数据和对应的业务逻辑被封装到同一个类中

分布式微服务架构

随着微服务架构理念的提出,单体架构向分布式微服务架构演进。微服务的设计目的是为了让大型软件系统解耦。将不同职责的服务独立部署,从而实现服务内部高内聚,服务之间低耦合的效果,让开发变得更为灵活。

这种架构的问题:
微服务的拆分困难,微服务到底应该如何拆分和设计呢?微服务的边界应该在哪里?

我们可以利用 DDD 设计方法来建立领域模型,划分领域边界,再根据这些领域边界从业务视角来划分微服务边界。

DDD的优点

  • 领域模型中的实体只反映业务,和任务技术实现无关,像MVC架构中的贫血模型无法反映业务,不知道这个实体跟哪些业务相关联,使得我们不敢修改这实体。
  • 领域模型确保了我们的业务逻辑都在一个模型中,都在一个地方,这样对提高软件的可维护性,业务可理解性以及可重性都有很好的帮助。
  • 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分。
  • 领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息因为大家面向的都是同一个模型,所以可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求;

领域驱动设计的最大价值是让我们告别从面向过程式的思想(天马星空,想到哪写到哪)转化为基于系统化的模型驱动思维。

基本概念

领域

领域:
DDD 的领域就是这个边界内要解决的业务问题域
领域往往就是业务的某一个部分 , 例如电商的销售部分、物流部分、供应链部分等, 这些对于电商来说就是各个领域(模块),领域主要作用就是用来驱动范围, DDD 会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。

子域:相对的一个概念, 我们可以将领域进行进一步的划分 , 这时候就是子域, 甚至可以对子域继续划分形成 子子域(依旧叫子域)。
image.png

实体和值对象

实体:
实体以 DO(领域对象)的形式存在,拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致(唯一标识)。实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现。简单来说就是有唯一标识+业务行为方法。

值对象:
实体相对应的就是值对象,如果没有唯一标识就是值对象。值对象一般是嵌套在实体里面的。嵌套方式可能有两种,一种是直接嵌套整个Java对象,二是嵌套一个json对象。其次值对象一般是不会改变的,变化的时候也是整体替换。值对象没有太多的业务行为更多的是对实体的一个修饰和描述,离开了实体就没有任何存在的业务意义

实体可以理解为一张数据库表,必须有主键。值对象没有主键,依附于实体而存在,比如用户实体下住址对象,一般在数据库中已 json 字符串的形式存在;最常见的值对象是枚举。

案例 1:以属性嵌入的方式形成的人员实体对象,地址值对象直接以属性值嵌入人员实体中。
image.png
案例 2:以序列化大对象的方式形成的人员实体对象,地址值对象被序列化成大对象 Json 串后,嵌入人员实体中。
image.png

聚合和聚合根

聚合根
聚合本身也是一个实体,聚合可以包含其他实体,其他实体不能脱离聚合而单独提供服务,比如一篇文章下的评论,评论必须从属于文章,没有文章也就没有评论。仓库层(repository)也必须是以聚合为核心提供服务的。

聚合
聚合就是由业务和逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化。
领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,它用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。

如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。

image.png

限界上下文

用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。这个边界定义了模型的适用范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。

正如电商领域的商品一样,商品在不同的阶段有不同的术语,在销售阶段是商品,而在运输阶段则变成了货物。同样的一个东西,由于业务领域的不同,赋予了这些术语不同的涵义和职责边界,这个边界就可能会成为未来微服务设计的边界。看到这,我想你应该非常清楚了,领域边界就是通过限界上下文来定义的
边界体现在以下几方面:

  • 领域逻辑层:确定了领域模型的业务边界,维护了模型的完整性与一致性,从而降低系统的业务复杂度;
  • 团队合作层:限界上下文一般也是用户换分团队的依据;
  • 技术实现层:限界上下文可当成是微服务的划分边界;

领域服务

单个实体对象能处理的逻辑放到实体里,多个实体或有交互的场景放到领域服务里。
领域服务可不可以调用仓储层或外部接口? 可以,但不能直接和领域服务代码放一起,领域服务模块存放API,实现放基础层(infrastructure)。
领域服务对象不建议直接以聚合名+DomainService命名,而要以操作命令关联,比如用户保存服务命名为:UserSaveService, 审核服务:UserAuditSerivce。
可以使用领域服务的情况:

  • 执行一个显著的业务操作
  • 对领域对象进行转换
  • 以多个领域对象作为输入参数进行计算,结果产生一个值对象

DDD分层架构

从三层架构向 DDD 分层架构演进的过程

image.png

  • DDD 分层架构在用户接口层引入了 DTO,给前端提供了更多的可使用数据和更高的展示灵活性。
  • DDD 分层架构对三层架构的业务逻辑层进行了更清晰的划分,改善了三层架构核心业务逻辑混乱,代码改动相互影响大的情况。
  • DDD 分层架构将业务逻辑层的服务拆分到了应用层和领域层。应用层快速响应前端的变化,领域层实现领域模型的能力。
  • 三层架构数据访问采用 DAO 方式;DDD 分层架构的数据库等基础资源访问,采用了仓储(Repository)设计模式,通过依赖倒置实现各层对基础资源的解耦。

仓储又分为两部分:仓储接口和仓储实现。仓储接口放在领域层中,仓储实现放在基础层。原来三层架构通用的第三方工具包、驱动、Common、Utility、Config 等通用的公共的资源类统一放到了基础层。

整体架构

2-02.png

  • 接口层
    • 接口服务位于用户接口层,用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给应用层。
  • 应用层{application}
    • 应用服务位于应用层。用来表述应用和用户行为,负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的拼装。
    • 应用服务可对微服务内的领域服务以及微服务外的应用服务进行组合和编排,或者对基础层如文件、缓存等数据直接操作形成应用服务,对外提供粗粒度的服务。
  • 领域层{domain}
    • 领域服务对同一个实体的一个或多个方法进行组合和封装,或对多个不同实体的操作进行组合或编排,对外暴露成领域服务。**领域服务封装了核心的业务逻辑。实体自身的行为在实体类内部实现,向上封装成领域服务暴露。 **
  • 基础层{infrastructure}
    • 基础服务位于基础层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响。
    • 基础服务主要为仓储服务,通过依赖反转的方式为各层提供基础资源服务,领域服务和应用服务调用仓储服务接口,利用仓储实现持久化数据对象或直接访问基础资源。

模块搭建

2-03.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/4092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Eclipse切JRE环境后如何恢复- Unrecognized option: --enable-preview

场景 使用switch 新特性 配合 lambda 练习小案例 // 需求: 1 2 3 -> 一、二、 三 int num 1; switch ( num) {// jdk13 可以缺省 break 并且 单语句可以省略 花括号 case 1 -> { System.out.println("一"); }case 2 -> System.out.p…

[附源码]计算机毕业设计JAVAjsp宠物店管理系统

[附源码]计算机毕业设计JAVAjsp宠物店管理系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybat…

Mybatis-Plus知识点[MyBatis+MyBatis-Plus的基础运用]

目录 前言 一、了解Mybatis-Plus 1.简介 2.Mybatis-Plus具有的特性 3.支持数据库 4.框架结构 5.官网链接 二、快速开始 2.1.创建数据库以及表 2.2.创建工程 2.3 MybatisMybatis-Plus的使用 2.3.1创建一个itcast-mybatis-plus-simple的maven项目 2.3.2写UserMapper接口 2.3.3写U…

北京化工大学数据结构2022/11/3作业 题解

目录 问题 A: 二叉树非递归前序遍历-附加代码模式 问题 B: 二叉树非递归中序遍历-附加代码模式 问题 C: 二叉树非递归后序遍历-附加代码模式 问题 D: 求二叉树中序遍历序根节点的下标 问题 E: 根据前序中序还原二叉树 问题 F: 算法6-12:自底向上的赫夫曼编码 …

ServletConfig和ServletContext接口

一、ServletConfig接口详解 1、简介 Servlet 容器初始化 Servlet 时,会为这个 Servlet 创建一个 ServletConfig 对象,并将 ServletConfig 对象作为参数传递给 Servlet 。通过 ServletConfig 对象即可获得当前 Servlet 的初始化参数信息。一个 Web 应用中…

微电网优化调度(风、光、储能、柴油机)(Python代码实现)

💥💥💥💞💞💞欢迎来到本博客❤️❤️❤️💥💥💥 ​ 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻…

【Linux命令】文件和目录权限

【Linux命令】文件和目录权限 权限查看 众所周知,可以使用 ls -l 来查看文件和目录的详细信息,那么输出的东西是什么呢? 我们先来看 文件类型: -:普通文件;d:目录文件;b&#xff…

网络协议:TCP三次握手与四次挥手

本篇内容包括:TCP/IP 传输协议(TCP/IP 传输协议简介,IP 协议,UDP 协议,TCP 协议介绍),TCP 的三次握手、TCP 的四次挥手 以及 TCP 协议是怎么保证有效传输等内容。 一、TCP/IP 传输协议 1、TCP/…

【仿牛客网笔记】 Redis,一站式高性能存储方案——Redis入门

Redis可以开发对性能要求较高的功能。还可以利用Redis重构我们现有的功能。 NoSQL关系型数据库之外的统称。 快照有称为RDB 以快照的形式 不适合实时的去做,适合一段时间做一次。 日志又称AOF 以日志的形式每执行一次就存入到硬盘中,可以做到实时的存储以…

JAVA外卖订餐系统毕业设计 开题报告

本文给出的java毕业设计开题报告,仅供参考!(具体模板和要求按照自己学校给的要求修改) 选题目的和意义 目的:本课题主要目标是设计并能够实现一个基于java的外卖点菜系统,管理员通过后台添加菜品&#xf…

卷积神经网络CNN

卷积神经网络CNN CNN通常用于影像处理 为什么需要CNN 为什么需要CNN,我用普通的fully connected的反向传播网络进行图像训练会怎样 需要过多参数 假设一张彩色的图为100100的,那么像素点就是1001003,那么输入层为三万维 假设下一层隐含层有…

移动Web:Less 预处理及Koala工具

css 预处理器,后缀名为 .less。 less 代码无法被浏览器识别,实际开发需要转换成 css,使用 liink 标签引入 css 文件。 插件工具 Easy Less VS Code 内置插件(less 文件保存自动生成 css 文件) 更改编译后 css 存储路径…

华清远见11.7

系统移植开发阶段部署 1.准备文件,由于内核只支持安全的启动模式,要准备u-boot镜像文件u-boot-stm32mp157a-fsmp1a-trusted.stm32 TF-A镜像文件tf-a-stm32mp157a-fsmp1a-trusted.stm32 linux内核镜像文件uImage和stm32mp157a-fsmp1a.dtb 根文件系统r…

QT 中多线程实现方法总结

第一: 用QtConcurrentRun类,适合在另一个线程中运行一个函数。不用继承类,很方便 第二:用QRunnable和QThreadPool结合。继承QRunnable,重写run函数,然后用QThreadPool运行这个线程。缺点是不能使用信号和槽…

html5 -- canvas使用(1)

canvas 设置canvas标签 添加宽高 默认单位为px <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport&…

荧光标记氨基酸:荧光标记DL-天门冬氨酸,荧光标记甘氨酸-DL-天冬氨酸,DL aspartic acid labeled

产品名称&#xff1a;荧光标记甘氨酸-DL-天冬氨酸&#xff0c;DL aspartic acid labeled 甘氨酸-DL-天冬氨酸是一种化学物质&#xff0c;化学式是C6H10N2O5&#xff0c;分子量是208.17。 DL-天门冬氨酸(DL-Asp)在医药方面有着重要的用途,可用于合成DL-天门冬氨酸钾镁盐(脉安定…

云原生之K8s—yaml文件

目录 一、K8S支持的文件格式 1、yaml和json的主要区别 二、YAML 2.1、查看API资源版本标签 2.2、编写资源配置清单 编写nginx-test.yaml资源配置清单 创建资源对象 查看创建的pod资源 创建资源对象 网页访问一下 K8S中的port概述 创建yaml文件模板 查看生成yaml格式…

【python的静态方法,classmethod方法和__call___魔法方法】

classmethod魔法方法和staticmethodstaticmethod&#xff0c;静态方法classmethod&#xff0c;绑定类方法__call__&#xff0c;可调用类类方法staticmethod&#xff0c;静态方法 在python中&#xff0c;使用静态方法可以实现不需要实例化对象的绑定就可以直接调用的函数&#…

Linux系统编程·进程概念

你好&#xff0c;我是安然无虞。 文章目录自学网站上文回顾进程控制块—PCB查看进程初识系统调用初始fork函数练习题自学网站 推荐给老铁们两款学习网站&#xff1a; 面试利器&算法学习&#xff1a;牛客网 风趣幽默的学人工智能&#xff1a;人工智能学习 首个付费专栏&…

添加滚动彩色提醒通知公告代码

分享一个动态的滚动多样化的彩色提醒通知公告&#xff0c;代码是自适应的&#xff0c;放在很多地方都可以用&#xff0c;在wordpress、emlog等建站cms中&#xff0c;都可以在自定义侧边栏中&#xff0c;用来网站、博客的美化也是非常不错的选择。 使用说明: wordpress&#xff…