DDD领域驱动设计系列-原理篇-战术设计

概述

上篇战略设计产出了领域及问题域领域模型;详见:DDD领域驱动设计系列-原理篇-战略设计-CSDN博客

战术设计篇聚焦如何落地,包含实际解决方案模型落地,架构分层(Clean,CQRS),Reposity模式落地实践(如何维护聚合);

战略设计输入

领域划分

划分4大域:结算用户域,计费,清算,结算;

问题域领域模型

战术设计-解决方案模型

解决方案模型可以从性能及实际落地因素来考虑;在结算中由于实际要通过接收交易确认收货消息来触发结算,出于保存结算时的原始数据快照便于后续有据可依这里抽出结算收单模型

这样最终的解决方案模型如下;

战术设计-架构分层

分层架构上是采用传统MVC还是DDD的六边型,Clean架构或者洋葱架构?

结论是:使用洋葱架构,原因:以领域实体为核心沉淀业务逻辑,外层依赖内层;架构上分为application service(业务流程编排),domain service(域服务),domain实体,以及入口服务&基础设施及外部业务依赖;

这样设计好处:1、基础设施变化不影响上层业务逻辑代码;2、更易理解维护及业务逻辑复用:业务逻辑沉淀在领域实体;

架构结果

各分层架构介绍

MVC

controller,service及dao层;缺点:1、所有的业务逻辑都写在service,复用度及可理解性不够;2、service直接依赖于Dao,当dao层实现有变化导致service变化;;

六边型

六边型核心思想是抽离业务入口为适配器入口适配器依赖于应用核心接口;同时应用核心依赖于基础设施及外部业务系统接口基础设施实现依赖于应用核心

这样好处较MVC架构来讲当基础设施实现变化不会影响应用核心,eg:消息由rabbitMq切换成rocketMq,上层应用核心代码不用变;

Clean架构

和六边型思路一致:分离基础设施&外部依赖;区别是明确定义了以领域实体为核心,外层是服务;

洋葱架构

更进一步定义了域服务及流程服务application service;基础逻辑与上述六边型&clean架构一致:基础设施&外部依赖可变化但不影响应用核心逻辑代码;

战术设计-CQRS

传统我们查询也会经过applicationService及domainService,但有时查询需要的内容不仅仅是领域模型此时就会导致领域模型耦合了和领域无关的内容;如订单列表展示需要商户额外的地点信息;

这里使用CQRS(Command Query Responsibility Segregation)架构模式;

查询方面直接由Api层查询reposity,减少中间层次转换&减少查询逻辑对于领域模型的入侵

战术设计-Reposity模式使用

为什么要用Reposity模式?

原因:1、解决传统service直接依赖Dao层导致Dao如果变化影响service代码大量改动;2、领域模型与持约化DO本身不是一对一等价关系,如合约领域模型实体Entity对应存储时涉及合约DO及合同条款DO;

Reposity分层架构

Domain Service层做为需求方负责制定需要的reposity存储接口,由Repsoity模块来进行实现;Reposity在实现的时候可对一个模型对象拆成多个DO存储或多个模型合成一个DO;

多个模型Entity对应一个DO场景:交易主单及子单是是多个模型,考虑到复用表结构,reposity在实现时会将主单与子单合统一转成一个交易表DO进行存储;

一个模型Entity对应多个DO场景:商品表考虑到性能会有商品主表及商品扩展表,在模型上商品是一个Entity,但在持久化时会拆成商品主表DO及商品扩展表DO进行持久化;

Reposity注意事项

标准的reposity接口有:save,query方法;其中save入参是领域模型Entity,如交易单存储入参是OrderModel,OrderModel包含了主单及子单;save方法通过聚合根entity是否有id来判断是插入还是更新;

但有时聚合根entity中有部分实体是没变化的,这个不需要进行更新,这个解决方案有变更追踪方案;

变更追踪原理:将入参的entity与数据库查询出来的entity进行比较(所有字段值)如果有变化才做更新;变更追踪方案有一定的复杂度(复杂度上来容易出问题),所以在实现时个人更倾向于由域服务决定要更新什么

比如交易支付场景对外提供交易支付接口,入参是:交易主单+交易子单;域服务这层针对入参子单进行处理(对子单调用支付域进行支付),最新调用reposity save时传入当前主单及当前支付的交易子单(而不是全部的交易子单)进行子单状态更新;

总结

本章介绍了DDD战术设计,描述了解决方案模型落地&分层架构选型&Reposity实现;

其中Reposity实现部分大的分层依赖是合理的,对于提升更新性能引入变更追踪导致的复杂度需要辩证去看

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

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

相关文章

04-C++ 类和对象-02

类和对象-02 1. this 指针 1.1 概念: 谁调用this所在的函数,this就存储谁的地址,即指向谁 。 1.2 特点: 在当前类的非静态成员函数中调用本类非静态成员时,默认有this关键字静态成员函数,没有this指针…

Neovim+ctag浏览、编辑源代码

Neovimctag浏览、编辑源代码 一 配置安装vim及 ctags vim应该可以不用装,直接装neovim,这里我是先装了vim再装的neovim Ctags必须装,后面用neovim telescope索引函数时才有效 vim复制系统粘贴板:vim输入模式下,按shi…

低功耗16位MCU:R7F100GLL3CFA、R7F100GLN2DLA、R7F100GLN3CFA、R7F100GLN2DFA是新一代RL78微控制器

产品介绍: RL78/G23低功耗MCU可在41μA/MHz CPU运行频率下工作,功耗低,停止4KB SRAM保持时为210nA。该MCU设有snooze模式排序器,可显著降低间歇工作时的功耗。RL78/G23组具有1.6V至5.5V宽工作电压范围,频率高达32MHz。…

bean生命周期源码(三)

书接上文 文章目录 一、Bean的销毁逻辑1. 简介2. Bean销毁逻辑的注册3. Bean的销毁过程 一、Bean的销毁逻辑 1. 简介 前面我们已经分析完了Spring创建Bean的整个过程的源码,在创建bean的核心方法中doCreateBean这一个核心方法中,在方法的最后面有这么…

SpringCloudAlibaba Seata在Openfeign跨节点环境出现全局事务Xid失效原因底层探究

原创/朱季谦 曾经在SpringCloudAlibaba的Seata分布式事务搭建过程中,跨节点通过openfeign调用不同服务时,发现全局事务XID在当前节点也就是TM处,是正常能通过RootContext.getXID()获取到分布式全局事务XID的,但在下游节点就出现获…

ros2+gazebo+urdf:ros2机器人使用gazebo的urdf文件中的<gazebo>部分官网资料

原文链接SDFormat extensions to URDF (the gazebo tag) — Documentation 注意了ros2的gazebo部分已经跟ros1的gazebo部分不一样了: Toggle navigation SpecificationAPIDocumentationDownload Back Edit Version: 1.6 Table of C…

我在代码随想录|写代码Day-Day之总结篇

我是用笔手写的我觉得这样可以对个人记忆会更好,而且理解更深解释也更清楚 下面是手写笔记 总结部分----- 第一章 二分 二分模版 图片可能反了下不过没有关系 图形打印模版题 第二章 链表 链表基本操作和疑问 链表代码操作和解析----5大操作 删除部分 对结点的操作 反了反了…

关于个人Git学习记录及相关

前言 可以看一下猴子都能懂的git入门,图文并茂不枯燥 猴子都能懂的git入门 学习东西还是建议尽可能的去看官方文档 权威且详细 官方文档 强烈建议看一下GitHub漫游指南及开源指北,可以对开源深入了解一下,打开新世界的大门! …

若依SQL Server开发使用教程

1. sys_menu表中的将菜单ID修改为自动ID,解决不能增加菜单的问题,操作流程如下: 解决方案如下 菜单栏->工具->选项 点击设计器,去掉阻止保存要求更新创建表的更改选项,点确认既可以保存了 2 自动生成代码找不表的解决方案…

C语言--直接插入排序【排序算法|图文详解】

一.直接插入排序介绍🍗 直接插入排序又叫简单插入排序,是一种简单直观的排序算法,它通过构建有序序列,对于未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入。 算法描述: 假设要排序…

idea 找不到 Free MyBatis plugin

idea 找不到 free mybatis plugin 可以使用mybatisX替换: 插件安装成功后,重启idea。

【English】水果单词小小汇总~~

废物研究生,只要不搞科研干啥都是开心的,啊啊啊啊啊科研要命。作为一个水果怪(每天不吃水果就要命的那种哈哈哈哈)突然发现竟然就知道什么apple、banana、orange!惭愧惭愧,正好兴致正浓,来整理一…

Java HashMap在遍历时删除元素

文章目录 1. HashMap数据结构1.1 数组单向链表红黑树1.2 指定初始容量,省去多次扩容步骤1.3 获取map内容:Map.Entry 2. 遍历集合时删除元素3. computeIfAbsent()方法 1. HashMap数据结构 jdk是1.8版本 HashMap 线程不安全 ConcurrentHashMap 线程安全 1.…

jvm_下篇_补充_MAT从入门到精通

MAT从入门到精通 概述安装mac安装指定jdk配置内存 使用配置获取dump文件Overview下功能解释HistogramDominator TreeLeak SuspectsOverview功能说明结尾Thread_Overview OQLHeap Dump OverviewFind Object by address 概述 尽管JVM提供了自动内存管理的机制,试图降…

golang的jwt学习笔记

文章目录 初始化项目加密一步一步编写程序另一个参数--加密方式关于StandardClaims 解密解析出来的怎么用关于`MapClaims`上面使用结构体的全代码实战项目关于验证这个项目的前端初始化项目 自然第一步是暗转jwt-go的依赖啦 #go get github.com/golang-jwt/jwt/v5 go get githu…

小狐狸ChatGPT系统 H5前端底部菜单导航文字修改方法

小狐狸ChatGPT系统后端都前端都是编译过的,需要改动点什么非常难处理,开源版修改后也需要编译后才能使用,大部分会员也不会使用,像简单的修改下底部菜单文字、图标什么的可以对照处理。这里以小狐狸ChatGPT系统1.9.2版本H5端为例&…

Unity向量按照某一点进行旋转

Unity向量按照某一点进行旋转 一、unity的旋转二、向量按照原点进行旋转注意案例 三、向量按照指定位置进行旋转案例 一、unity的旋转 首先要知道一点就是在Unity的旋转中使用过四元数进行旋转的,如果对一个物体的rotation直接赋值你会发现结果不是你最终想要的结果…

Kubectl 部署有状态应用(上)

前面介绍了Deployment以及如何部署无状态应用。 Kubectl 部署无状态应用Deployment Controller详解(上)Deployment Controller详解(下) 本文将继续介绍如何在k8s上部署有状态应用。 有状态和无状态服务的区别 无状态&#xff…

数组元素反序

和前面的字符串逆向输出有异曲同工之妙 第一位和最后一位交换位置,然后用比大小循环 那么接下来修改一下这个程序,我们接下来解释一下p的概念 画图解释: 在最前面的 定义的时候,我们将p(0)定义在了1上&…

四、Spring IoC实践和应用(基于配置类方式管理 Bean)

本章概要 基于配置类方式管理 Bean 完全注解开发理解实验一:配置类和扫描注解实验二:Bean定义组件实验三:高级特性:Bean注解细节实验四:高级特性:Import扩展实验五:基于注解配置类方式整合三层…