DDD在项目中的应用与结构的划分
更新: 3/15/2025 字数: 0 字 时长: 0 分钟
零零散散的学习了快一个星期的DDD了,是时候也该实践一下DDD了
(这一部分是我在pull下来了bitbone老哥的课程源码后自己尝试在自己的项目中落地的感悟)
聚合
首先是聚合,聚合的首要目的究竟是干什么?
首先,我们必须要了解的是,聚合是一个充血模型,因此我们的聚合渴望干到的事只有一个,那就是聚合领域下大部分的业务都可以由聚合自己所持有的字段完成(不能完成的后面会说),聚合会将这些业务封装为方法
因此我们的聚合既有字段,也有业务逻辑。
这里的一个严重的转变是——聚合所持有的字段是要存放到一个SQL或者NoSQL里的,但是聚合一般不会给到用户查看,只是我们用来处理业务的。
这也是CQRS对我们存储的规范,即数据的划分不再想当然,而是按照Command和Query分成两个表
仓储
仓储的任务是查找我们的聚合,将聚合拿出,然后等待执行业务使用。亦或是仓储将聚合一次放入SQL中
注意,读模型有时也会用到仓储
Command
Command向仓储去索要我们的聚合,然后使用聚合提供的方法完成业务
Policy
Policy是用来作为中转站,持有多个仓储,基于该特性,Policy可以完成业务中一个聚合难以完成的业务
Event
Event是发生的事实,在风暴图中他可能会引发另一个Command,这一块是在Policy中完成的,因此这里Event的任务就只剩下了通知读模型去做出修改
一个最简单的尝试
什么是DDD?
领域驱动软件设计就是DDD!!!
因此我们的代码结构其实不需要上面这么复杂(或者说是标准?)
我们真正要实现的只有:
- 让仓储去读取聚合
- 让聚合或聚合间合作去完成大多数的业务逻辑,业务逻辑不再过程式的写在一个Service中,而是由各个聚合(对象)在自己的方法中完成(封装),这才是DDD/面向对象设计的核心
- 不涉及业务逻辑的对象单独处理(这里可能不好理解,我举个例子,比如你的观看记录,这个东西不像你的会员身份一样会对你的任何操作产生印象,因此就不会涉及任何业务逻辑,他只是展示给你,因此他就是一个纯粹的读模型,这种模型我们不用去涉及聚合,单纯的CRUD就行)
什么是读模型的范围?
一个疑惑是什么是读模型,像刚刚的观看记录就是一个显然的读模型,但例子常常不会这么绝对
举个显而易见的例子——用户信息
用户信息是读模型吗?
有人说是!因为用户信息只是展示给用户看的,没啥业务逻辑。
有人说不是!因为用户信息有长度限制,有违规词限制!
那究竟是不是呢?
我最开始也在想这个问题,直到一个晚上我躺床上回味的时候突然想明白了!这实际上就是一个限界上下文的问题。对于他人而言,你的用户信息肯定就是一个读模型,因为对这个人使用系统产生不了影响。而对于持有该信息的用户来说,这个信息可能会影响到他使用系统,因此就不是一个读模型。
所以结论我的结论是:
聚合和读模型最大的区别是:是否会对系统产生持久性的影响!(注意:这里的影响我认为应该分为两个部分,一个是围观/个人层面,是否会针对某个用户使用系统时产生影响,一个是宏观层面,是否对部分用户使用系统时产生影响,这两个只要有一个存在,那就算是会影响系统)
那我们怎么去鉴别持久还是不持久呢?
“是否会对系统产生持久性的影响”我认为分为以下情况
是否会用到这个字段来完成一些不是针对该字段CRUD操作的操作
一个字段完成不了,需要多个字段甚至多个聚合共同执行一些操作或者判断才能完成的操作
简单来说就是只要字段会被用来完成不是对自己修改的操作,那他就不是一个单纯的读模型