当前位置: 首页 > article >正文

通俗地讲述DDD的设计

通俗地讲述DDD的设计

  • 前言
  • 为什么要使用DDD
  • DDD架构分层重构实践
    • 关键问题解决方案
      • 通过​​领域事件机制​​解耦服务依赖:
      • 防止逻辑下沉
    • 领域划分
      • 电商场景下的领域划分
  • 结语
  • 完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!

前言

平时我们在谈论到DDD(驱动领域设计)的时候,往往感觉讳莫如深,特别是市面上对于它的定义、落地实现策略这些,都没有明确的解释,似乎一百个人有一百种解释,以至于我们在设计架构层级以及具体代码实现时,都不会用到DDD的设计思想,于是本文会按笔者理解DDD的概念以及设计原则去通俗描述,尽量让诸位培养成下意识使用它的习惯;

为什么要使用DDD

在传统分层架构(API层-业务层-Service层-DAO层)实践中,我们常遇到以下典型问题:

​​Service层相互调用导致的链式灾难​​(如A->B->C->D的深度调用)
​​Common模块过度抽象引发的架构退化​​(业务层公共代码下沉导致Service层失去业务语义)
​​调用关系失控​​(业务调用可能意外穿透到DAO层,层级边界模糊)
这些问题的本质是​​业务逻辑与技术实现耦合度过高​​,而领域驱动设计(Domain-Driven Design)为解决这些问题提供了新的视角。

DDD架构分层重构实践

// 示例包结构
com.example
├── api        // API层:接口定义、DTO转换
├── application // 业务层:业务流程编排
├── domain     // 领域层:核心业务逻辑
└── infra      // 基础设施层:数据库/外部服务访问

API层​​:定义对外契约,完成DTO与领域对象的双向转换。建议采用门面模式隔离外部参数与内部模型。
​​业务层​​:编排领域服务,处理跨领域协作。此处应保持无状态,仅包含流程控制逻辑。
​​领域层​​:封装业务规则(对于某一功能具体的代码实现),通过聚合根维护领域完整性。建议每个领域模块独立成包(如order/payment)。
​​DAO层​​:重构为基础设施层,实现仓储接口,支持多数据源适配。
注意:ddd的事务管理应该放在业务层,还是领域层,各有各的风险 ,业务层因为是编排调用多个服务,就会有长事务的问题,而在领域层则是有一致性问题;(因为如果把事物放在application层,增删改之间掺杂比较耗时的其他操作就会造成大事物。放在domain层,其他领域可能会有关联)

关键问题解决方案

通过​​领域事件机制​​解耦服务依赖:

// 订单创建后发布领域事件
public class OrderService {@Transactionalpublic void createOrder(Order order) {orderRepository.save(order);eventPublisher.publish(new OrderCreatedEvent(order.getId()));}
}// 库存服务监听事件
@Component
public class InventoryHandler {@EventListenerpublic void handle(OrderCreatedEvent event) {inventoryService.lockStock(event.getOrderId());}
}

防止逻辑下沉

建立​​分层防护机制​​:

在领域层定义仓储接口
基础设施层实现具体仓储
通过依赖注入控制反转

// 领域层定义接口
public interface OrderRepository {Order findById(OrderId id);
}// 基础设施层实现
@Repository
public class JpaOrderRepository implements OrderRepository {// 具体实现
}

领域划分

ddd的精华就是在于领域划分,而领域模型的设计目的
1、业务和代码要对齐,不至于一个简单的业务,要用成堆的代码解决,还要回想整个代码流程才明白这个业务;
2、让测试、开发、产品对某一个bug的描述要一致;
3、减少修改难度和影响面;
说明:
聚合根:就是bo、vo、do这些不同层有自己的返回对象类;
领域调用其他领的中间会有一个防腐层(防腐层是指对参数的转换,把这个参数转换抽取出来,传递的就是聚合根,有了防腐层是为了防止腐化其他领域的代码)

电商场景下的领域划分

┌──────────────┐ ┌─────────────┐
│ 订单域 │◄─────►│ 支付域 │
│ - 订单创建 │ │ - 支付处理 │
│ - 订单状态机 │ └─────────────┘
└───────┬──────┘

┌──────────────┐
│ 库存域 │
│ - 库存扣减 │
│ - 库存预警 │
└──────────────┘
不同层级之间传递参数,要注意转换和收敛,就是上层调用多个下层,也不要直接一个参数对象从头走到尾,而是将对象所需属性转换成需要相应的对象;

结语

DDD的真正价值在于​​建立业务与技术的统一语言​​。建议采用渐进式改造:

从核心子域开始试点
建立领域字典统一术语
通过持续重构优化模型
技术架构的演进永无止境,但通过DDD建立的清晰领域边界,能使系统在业务快速变化中保持足够的弹性。

完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!

相关文章:

通俗地讲述DDD的设计

通俗地讲述DDD的设计 前言为什么要使用DDDDDD架构分层重构实践关键问题解决方案通过​​领域事件机制​​解耦服务依赖:防止逻辑下沉 领域划分电商场景下的领域划分 结语完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,…...

【Redis】通用命令

使用者通过redis-cli客户端和redis服务器交互,涉及到很多的redis命令,redis的命令非常多,我们需要多练习常用的命令,以及学会使用redis的文档。 一、get和set命令(最核心的命令) Redis中最核心的两个命令&…...

网络安全技术文档

网络安全技术文档 1. 概述 网络安全是指通过技术手段和管理措施,保护网络系统的硬件、软件及其数据不受偶然或恶意破坏、更改、泄露,确保系统连续可靠运行,网络服务不中断。 2. 常见网络威胁 2.1 攻击类型 DDoS攻击:分布式拒…...

微前端随笔

✨ single-spa: js-entry 通过es-module 或 umd 动态插入 js 脚本 ,在主应用中发送请求,来获取子应用的包, 该子应用的包 singleSpa.registerApplication({name: app1,app: () > import(http://localhost:8080/app1.js),active…...

【36期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股当天逐笔大单交易数据及接口API说明文档

​ 在量化分析领域,实时且准确的数据接口是成功的基石。经过多次实际测试,我将已确认可用的数据接口分享给正在从事量化分析的朋友们,希望能够对你们的研究和工作有所帮助,接下来我会用Python、JavaScript(Node.js&…...

C++中的浅拷贝和深拷贝

浅拷贝只是将变量的值赋予给另外一个变量,在遇到指针类型时,浅拷贝只会把当前指针的值,也就是该指针指向的地址赋予给另外一个指针,二者指向相同的地址; 深拷贝在遇到指针类型时,会先将当前指针指向地址包…...

二叉树与红黑树核心知识点及面试重点

二叉树与红黑树核心知识点及面试重点 一、二叉树 (Binary Tree) 1. 基础概念 定义:每个节点最多有两个子节点(左子节点和右子节点) 术语: 根节点:最顶层的节点 叶子节点:没有子节点的节点 深度&#xf…...

GitHub 趋势日报 (2025年04月01日)

GitHub 趋势日报 (2025年04月01日) 本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星语言1punkpeye/awesome-mcp-serversA collection of MCP servers.⭐ 3280未指定2th-ch/youtube-musicYouTu…...

Java的SeleniumChromeDriver的常用方法

启动和关闭浏览器: driver.get(url):打开指定的URL。driver.quit():关闭浏览器并结束ChromeDriver会话。 元素定位: driver.findElement(By.id("elementId")):通过元素的ID定位。driver.findElement(By.cl…...

字符串、列表、元组、字典

字符串 双引号或者单引号中的数据,就是字符串 字符串输入 之前在学习input的时候,通过它能够完成从键盘获取数据,然后保存到指定的变量中; 注意:input获取的数据,都以字符串的方式进行保存,即…...

【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60‘ did not match any bands”

【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 文章目录 【GEE学习笔记】报错解决:“Image.selec…...

AI可以赋能的三农产品、机械与服务

三农赛道涵盖农业、农村和农民相关的产品与服务,涉及农资、农业机械、智能设备、农产品加工及数字化服务等多个领域。随着人工智能(AI)技术的飞速发展,AI正在通过赋能农业的生产、管理、销售等各个环节,推动传统农业向…...

ngx_timezone_update

定义在 src\os\unix\ngx_time.c void ngx_timezone_update(void) { #if (NGX_FREEBSD)if (getenv("TZ")) {return;}putenv("TZUTC");tzset();unsetenv("TZ");tzset();#elif (NGX_LINUX)time_t s;struct tm *t;char buf[4];s tim…...

车载诊断架构 --- 整车重启先后顺序带来的思考

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...

GESP C++三级 知识点讲解

C编程三级标准 (一)知识点详述 (1)了解二进制数据编码:原码、反码、补码。 (2)掌握数据的进制转换:二进制、八进制、十进制、十六进制。 (3)掌握位运算:与(&)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)的基本使用方法及原理。 (4)了解算法的概念与描述&…...

前端 vs 后端:技术分工详解——从用户界面到系统逻辑的全解析

前端&#xff08;Frontend&#xff09; 和 后端&#xff08;Backend&#xff09; 是软件开发中两个核心概念&#xff0c;分别对应用户直接交互的部分和系统背后的逻辑处理部分。它们共同构成完整的应用程序&#xff0c;但分工不同。 目录 一、前端&#xff08;Frontend&#xf…...

Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结

以下是 Redis 除了数据类型外的核心功能 的详细说明&#xff0c;包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结&#xff1a; 1. Redis 事务&#xff08;Transactions&#xff09; 功能描述 事务通过 MULTI 和 EXEC 命令将一组命令打包执行&#xff0c;保证…...

JavaScript智能对话机器人——企业知识库自动化

引言 内部知识管理常面临信息分散、查找困难的问题。本文将使用Node.js和虎跃办公的智能对话API&#xff0c;构建企业级知识问答机器人&#xff0c;支持自然语言查询和自动学习。 核心技术 自然语言处理&#xff08;NLP&#xff09;意图识别机器学习模型微调REST API集成 代…...

JS实现AES和DES

目录 目标 概述 DES AES 实战 JS实现DES JS实现AES 目标 了解AES和DES的特点并用JS实现。 概述 DES 翻译过来叫数据加密标准。它有5种加密模式&#xff08;CTR、OFB、CFB、CBC、ECB&#xff09;&#xff0c;在JS中&#xff0c;不同加密模式语法结构几乎一致&#xff0c…...

【C++11(下)】—— 我与C++的不解之缘(三十二)

前言 随着 C11 的引入&#xff0c;现代 C 语言在语法层面上变得更加灵活、简洁。其中最受欢迎的新特性之一就是 lambda 表达式&#xff08;Lambda Expression&#xff09;&#xff0c;它让我们可以在函数内部直接定义匿名函数。配合 std::function 包装器 使用&#xff0c;可以…...

Windows 10/11系统优化工具

家庭或工作电脑使用时间久了&#xff0c;会出现各种各样问题&#xff0c;今天给大家推荐一款专为Windows 10/11系统设计的全能优化工具&#xff0c;该软件集成了超过40项专业级实用程序&#xff0c;可针对系统性能进行深度优化、精准调校、全面清理、加速响应及故障修复。通过系…...

浅谈在HTTP中GET与POST的区别

从 HTTP 报文来看&#xff1a; GET请求方式将请求信息放在 URL 后面&#xff0c;请求信息和 URL 之间以 &#xff1f;隔开&#xff0c;请求信息的格式为键值对&#xff0c;这种请求方式将请求信息直接暴露在 URL 中&#xff0c;安全性比较低。另外从报文结构上来看&#xff0c…...

LightRAG实战:轻松构建知识图谱,破解传统RAG多跳推理难题

作者&#xff1a;后端小肥肠 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 2025防失业预警&#xff1a;不会用DeepSeek-RAG建知识库的人正在被淘汰_deepseek-embedding-CSDN博客 从PDF到精准答案&#xff1a;Coze…...

C++多线程编码二

1.lock和try_lock lock是一个函数模板&#xff0c;可以支持多个锁对象同时锁定同一个&#xff0c;如果其中一个锁对象没有锁住&#xff0c;lock函数会把已经锁定的对象解锁并进入阻塞&#xff0c;直到多个锁锁定一个对象。 try_lock也是一个函数模板&#xff0c;尝试对多个锁…...

垃圾回收——三色标记法(golang使用)

三色标记法(tricolor mark-and-sweep algorithm)是传统 Mark-Sweep 的一个改进&#xff0c;它是一个并发的 GC 算法&#xff0c;在Golang中被用作垃圾回收的算法&#xff0c;但是也会有一个缺陷&#xff0c;可能程序中的垃圾产生的速度会大于垃圾收集的速度&#xff0c;这样会导…...

Linux学习笔记——零基础详解:什么是Bootloader?U-Boot启动流程全解析!

零基础详解&#xff1a;什么是Bootloader&#xff1f;U-Boot启动流程全解析&#xff01; 一、什么是Bootloader&#xff1f;&#x1f4cc; 举个例子&#xff1a; 二、U-Boot 是什么&#xff1f;三、U-Boot启动过程&#xff1a;分为两个阶段&#x1f539; 第一阶段&#xff08;汇…...

Windows环境下开发pyspark程序

Windows环境下开发pyspark程序 一、环境准备 1.1. Anaconda/Miniconda&#xff08;Python环境&#xff09; 如果不怕包的版本管理混乱&#xff0c;可以直接使用已有的Python环境。 需要安装anaconda/miniconda&#xff08;python3.8版本以上&#xff09;&#xff1a;Anaconda…...

thinkphp8.0上传图片到阿里云对象存储(oss)

1、开通oss,并获取accessKeyId、accessKeySecret <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><tit…...

SSM婚纱摄影网的设计

&#x1f345;点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345; 项目视频 SS…...

1110+款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100+ Icons Easily Customize

1110款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100 Icons Easily Customize 产品特点 — 24 x 24 px 网格大小 — 2px 线条描边 — 所有形状都是基于矢量的 — 平滑和圆角 — 易于更改颜色 类别 &#x1f6a8; 警报和反馈 ⬆️ 箭头 &…...