【基于电商履约场景的 DDD 实战】DDD业务建模第二部分:履约的战术设计(梳理整个战术设计流程图)

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

基于电商履约场景的 DDD 实战

在这里插入图片描述

第二部分:战术设计

名词介绍

第二部分来说一下战术设计都要做哪些事情

在战术设计中,牵扯到了具体的类层面的设计,涉及到每一个上下文里有哪些类,类之间如何配合

在战术设计中,包含了:

  • 聚合(Aggregate):将多个联系很强的类聚合在一起,聚合后的东西就是一个聚合,下边的 Order 就是一个聚合

    public class Order {
      // 唯一表示
      private orderId;
      // 多个订单细节
      List<OrderItem> orderItems;
      // 发货地址
      DeliveryAddress deliveryAddress;
    }
    

  • 实体(Entity):实体比较好理解,就是实体类,比如对于订单来说,它的实体就是 Order 类,需要唯一标识

  • 值对象(Value Object):值对象是一种特定的实体,它代表了一个不可变的、没有唯一标识的对象。就比如在电商系统中,Money 是一个值对象,当存在多个 Money 对象时,只要他们的货币类型和金额相同,那它们就是相同的,值对象中通过属性值就可以判断是不是相同的,因此不再需要唯一标识

  • 仓储(Repository):将聚合数据、实体数据和持久层进行持久化的组件,通过仓储进行数据的查询、修改、保存等操作,包括和 MySQL、Redis、ES、MQ 进行交互

  • 领域服务(Domain Service):用于存放无法单独放在某个聚合中的一些业务逻辑

  • 业务组件(Business Component):业务组件就是一段业务逻辑,既不是聚合,也不是领域服务,就比如订单状态机,表示订单的不同状态,这就是一个业务组件

    // 订单状态及业务组件
    public class OrderStateMachine {}
    
  • 领域事件(Domain Event):通过领域事件来串联起整个业务,就比如通过订单支付事件(OrderPayedEvent)驱动发起履约的流程,订单上下文发布【订单支付事件】,履约上下文订阅【订单支付事件】,监听到事件发生后,就开始执行履约的流程

  • 命令(Command):由人驱动发起的命令,例如点击按钮、提交表单等等,这些都是命令

贫血模型和充血模型

这里先说一下贫血模型和充血模型的概念

  • 贫血模型

贫血模型就是我们之前使用 MVC 架构写出来的实体类的 class,这些 class 一般都是贫血模型

贫血指的是这些 class 中只存储一些数据,和数据库表中的字段是一一对应的,而对这些数据的一些业务逻辑操作,全部放在了其他地方(Service)

那么之前我们用 MVC 架构写出来的东西,业务逻辑全部封装在 Service 中,Domain 中的实体类中只有数据,没有业务逻辑,因此说 Service 是充血模型,Domain 是贫血模型

Service 中包装了太多的业务逻辑所导致的问题就是 Service 中的代码太多,导致代码看起来非常混乱

  • 充血模型

在 DDD 中,是 将聚合设计成充血模型 了,聚合其实就是一堆实体类的集合,将业务行为放在聚合中去,将业务逻辑从 Service 中提取出来,按照业务语义放到对应的聚合中去,比如说对于 Order 订单来说,保存订单的操作,可以放在 Order 这个聚合中去:

public class Order {
  // 唯一表示
  private orderId;
  // 多个订单细节
  List<OrderItem> orderItems;
  // 发货地址
  DeliveryAddress deliveryAddress;
  
  // 业务行为
  public void saveOrder(/*省略*/) {/*省略*/}
}

领域服务有什么用?

这里讲一下领域服务到底是干什么的:

上边讲了将一些业务逻辑给抽取到聚合中去,但是还有一些业务逻辑可能设计了多个聚合,并不只属于某一个聚合,而是作为一个业务组件存在的,因此不能抽取到某一个聚合中

那么可以再去设计一个领域服务 DomainService,将业务逻辑放到领域服务中去

如何验证你的 DDD 架构设计的好不好呢?

有一个很简单的方法就是,让产品经理或者不懂代码的人,来看你代码的流程,如果代码可以很清晰的还原出来业务语义,那么就证明你的 DDD 架构设计的非常好了!

履约上下文业务流程梳理

这里再来梳理一下履约中的业务流程,之后就开始对履约上下文进行战术设计了

  1. 接收订单:通过监听【订单支付成功】事件
  2. 保存订单:将订单相关数据保存在履约的上下文中
  3. 预分仓:先对订单分配一个距离比较近的仓库
  4. 风控拦截:通过风控上下文提供的接口,拦截有风险的请求
    1. 人工审核:将拦截到的风险请求给人工进行审核
    2. 审核通过、重分仓、取消订单:人工审核后,对订单状态进行更新
  5. 分物流:通过物流上下文提供的接口,分配一个合适的物流公司
  6. 下库房:通过仓储上下文提供的接口,将履约订单指派给指定的仓库

DDD 中的接口层和应用服务层

接口层, 是 DDD 最靠外的一个层次,用于向外部提供 Http 调用

而像 MQ 中的消费者,也算是接口层,是基于 MQ 事件消费的接口

当接口层收到外部了 Http 请求之后,可以通过防腐层做一些数据的适配,将外部数据转为内部数据,之后再去执行对应的一系列的业务逻辑

应用服务层,用于进行业务流程编排,就比如由 ApplicationService 来进行履约整个流程的编排,负责基于仓储、聚合、领域服务来执行各种各样的动作,完成整个业务流程中所需要执行的动作

DDD 战术设计细节

请添加图片描述

我将履约流程中的战术设计给画了出来,其实 DDD 业务建模中,最重要的就是战术设计

通过战术设计,基本上就将你负责的上下文的模型给建立好,通过战术建模就可以看出来

接下来对上边的这张战术设计的流程图介绍一下**(圆圈内的都是履约上下文)**:

  1. 首先订单上下文发布【订单支付成功】的事件,被履约上下文的监听器监听到,进入到 接口层 ,也就是履约上下文的入口
  2. 履约上下文的 应用服务层 负责整个履约链路的执行
  3. 首先是 保存履约单 ,这里就涉及到数据的持久化,交给 仓储 来做,其中履约单作为一个 聚合 包含了多个实体,以及一些 业务逻辑 (DDD 精华:将聚合设计为充血模型)
  4. 接下来就是风控拦截,调用风控上下文提供的 API,与风控上下文使用 conformist 映射关系,完全遵守风控的接口规范(因为不处于一个团队,风控团队按照自己的计划迭代接口)
  5. 接下来是预分仓和分物流,这里创建了一个履约的领域服务,因为这里边的业务逻辑没有办法单独放到某个聚合中去,将预分仓和分物流这两个逻辑抽取到领域服务中
    1. 预分仓:创建一个 Warehouses 仓库集合的业务组件和 Warehouse 仓库的业务组件,通过这两个业务组件执行一些仓库相关的业务操作,通过调用仓储上下文的 API 接口拿到仓库集合,并且挑选距离最近的仓库,之后再检查选出来的仓库库存是否充足,并锁定库存(调用仓储上下文的 API 接口)
    2. 分物流:和预分仓类似,这里就不重复说了

那么至此,履约的战术设计就已经完成了

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java笔记 --- 二、Stream流

二、Stream流 结合Lambda表达式&#xff0c;简化集合、数组的操作 获取Stream流对象 单列集合获取Stream流 双列集合获取Stream流 数组获取Stream流 一堆零散的数据获取Stream流 Stream流的静态方法of的形参是一个可变参数&#xff0c;可以传递零散数据&#xff0c;也可以传递…

【Python】02快速上手爬虫案例二:搞定验证码

文章目录 前言1、不要相信什么验证码的库2、以古诗文网为例&#xff0c;获取验证码1&#xff09;code_result.py2&#xff09;gsw.py 前言 提示&#xff1a;以古诗文网为例&#xff0c;获取验证码&#xff1a; 登录&#xff1a;https://so.gushiwen.cn/user/login.aspx 1、不…

【C++】类与对象(一)

前言 类与对象&#xff08;一&#xff09; 文章目录 一、面向对象和面向过程的对比二、类的引入2.1 C中的结构体2.2 类2.3 类定义方法2.4 修饰限定符2.5 封装2.6 类的实例化2.7 类对象的大小 三、this指针3.1 this 指针的使用 一、面向对象和面向过程的对比 面向过程编程是将程…

【Docker】nacos集群搭建Nginx负载均衡

目录 一、mysql安装与基操 1.1 数据准备 1.2 创建mysql与数据表 二、Nacos集群部署 2.1 创建nacos及配置 2.2 创建Nginx容器 一、mysql安装与基操 1.1 数据准备 拉取mysql docker pull mysql:5.7(版本) 定义挂载目录 mkdir -p /mysql/{conf,data,script} 配置my.c…

【排序4】探秘归并排序:提高程序效率的必备技巧

&#x1f60a;归并排序 &#x1f38a;1、基本思想&#x1f38a;2、代码示例&#x1f38a;3、非递归实现&#x1f38a;4、归并排序的性能分析&#x1f38a;5、归并排序的优缺点&#x1f38a;6、归并排序的应用场景&#x1f38a;7、总结 &#x1f38a;1、基本思想 归并排序&…

(笔记总结)C/C++语言的常用库函数(持续记录,积累量变)

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

【vue3源码】vue源码探索之旅:项目介绍

简言 记录下我眼中的vue源码项目。 gitHubvue3项目仓库 项目要求: vue版本 3.4.15nodeV18.12.0以上使用pnpm包管理器vitest测试框架Vue3 vue3是渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。 Vue 是一个框架,也是一个生态。其功能覆盖了大部分…

Spark运行架构以及容错机制

Spark运行架构以及容错机制 1. Spark的角色区分1.1 Driver1.2 Excuter 2. Spark-Cluster模式的任务提交流程2.1 Spark On Yarn的任务提交流程2.1.1 yarn相关概念2.1.2 任务提交流程 2.2 Spark On K8S的任务提交流程2.2.1 k8s相关概念2.2.2 任务提交流程 3. Spark-Cluster模式的…

HBase入门:运行机制

文章目录 HBase 系统架构客户端ZooKeeper 服务器Master 主服务器Region 服务器 Region 服务器工作原理用户读写数据的过程缓存的刷新StoreFile合并 Store 的工作原理HLog 的工作原理 HBase 系统架构 HBase 的系统架构包括客户端、ZooKeeper 服务器、Master 主服务器、Region服…

Linux文本三剑客---grep

grep&#xff08;从文本或字符串种过滤特定内容。&#xff09; 格式&#xff1a;Usage: grep [OPTION]... PATTERNS [FILE]... 常用选项&#xff1a; -E 等价于 egrep 扩展正则 -i 忽略大小写 -w 匹配单词 -o 仅显示匹配内容 -r 递归匹配 -c 统计匹配的行数 -v 取反 -n 行号 -A…

vue2 事件总线

原图下载&#xff1a;https://download.csdn.net/download/weixin_47401101/88788636

如何在Shopee平台上进行宠物类目的选品丨shopee宠物选品

在Shopee平台上进行宠物类目的选品是一个重要的任务&#xff0c;它直接关系到卖家的销售业绩和市场竞争力。为了成功选择适合的宠物用品&#xff0c;在选品过程中&#xff0c;卖家可以遵循以下策略&#xff1a; 先给大家推荐一款shopee知虾数据运营工具知虾免费体验地址&#…

ZYNQ AC7020C的“点LED”实验

一、创建 Vivado 工程 1、启动 Vivado 2、在 Vivado 开发环境里点击“Create New Project”&#xff0c;创建一个新的工程 3、弹出一个建立新工程的向导&#xff0c;点击“Next” 4、在弹出的对话框中输入工程名和工程存放的目录。需要注意工程路径“Project location”不能有…

瑞丽杂志引领潮流,VOSS眼镜概念店开启奢华新纪元!

近日&#xff0c;由《瑞丽》杂志社举办的2023第4届瑞丽轻奢品牌大赛&#xff0c;以“轻奢•悦藏”为主题的大赛已圆满结束&#xff0c;VOSS眼镜荣获&#xff1a;2023瑞丽轻奢品牌大赛「轻奢时尚风格奖」&#xff0c;作为眼镜行业唯一获此奖项的品牌&#xff0c;VOSS眼镜对此表示…

C++初阶入门之命名空间和缺省参数的详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.命名空间 2.1命名冲突的例子 2.2解决方案 2.3命…

QT发生弹出警告窗口

QTC开发程序弹出警告窗口&#xff0c;如上图 实施代码&#xff1a; #include <QMessageBox> int main() {// 在发生错误的地方QMessageBox::critical(nullptr, "错误", "发生了一个错误&#xff0c;请检查您的操作。");}上面的文字可以更改&#x…

(2024,预训练和微调扩散,图编码器,图特征与CLIP特征对齐)场景图到图像合成:集成 CLIP 指导与扩散模型中的场景图条件

Scene Graph to Image Synthesis- Integrating CLIP Guidance with Graph Conditioning in Diffusion Models 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1 扩…

配置ARP安全综合功能示例

组网图形 ARP安全简介 ARP&#xff08;Address Resolution Protocol&#xff09;安全是针对ARP攻击的一种安全特性&#xff0c;它通过一系列对ARP表项学习和ARP报文处理的限制、检查等措施来保证网络设备的安全性。ARP安全特性不仅能够防范针对ARP协议的攻击&#xff0c;还可以…

Servet的基础学习

Servet的基础学习 servet的简单介绍 Servlet 是运行在 Web 服务器或应用服务器上的程序&#xff0c;它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet&#xff0c;您可以收集来自网页表单的用户输入&#xff0…

插槽(64-67)

文章目录 插槽1.插槽 - 默认插槽(组件内可以定制一处结构)2.插槽 - 后备内容&#xff08;默认值&#xff09;3.插槽 - 具名插槽(组件内可以定制多处结构)4.作用域插槽(插槽的一个传参语法) 插槽 插槽分类:默认插槽和具名插槽 1.插槽 - 默认插槽(组件内可以定制一处结构) 作用…