领域驱动设计 pdf_什么是领域驱动设计?

什么是领域驱动设计?

你可能使用领域驱动设计(DDD)开发了一些项目。你可能很满意, 使用领域模型来开发领域业务。并且得意地展示给你的同事看,他们会说“666”。

但有的时候你使用领域模型你总觉得哪儿有点不对劲。你会嘀咕你可能遗漏了什么。 emmmm...但真的是这样吗?你发觉自己在问类似下面的这些问题:

  • 什么是领域模型?
  • 领域模型是怎么更新到数据库的呢?
  • 领域模型是否要引入一种架构模式?例如CQRS

当我刚开始使用领域模式的时候,我也同样被上面这些问题所困扰。 甚至当我写文档前几天,我也并没有扎实地掌握某些细节。 我经历了一些“啊哈”的开窍时刻,我想把这些分享给你。 这篇文章会深入讲解帮你明白上面问题的答案。

在看答案之前,我们需要先往后退一步。 这篇文章的目的不是给你一个要点清单,而是想帮你真正地领会领域模型。 其实我们并没有太多需要学习的,事实上,我们会花很多时间试图忘记某些已经习得的概念(unlearning)。

“忘记你已经学到的。” — Yoda

a30b7968b3a42a594b2b90d5e32b614f.png

这篇文章真的很长。它更像一本mini书,这也是我更喜欢的形式。


摘要

如果你不想阅读整篇文章,可以快速浏览这份摘要。如果你打算阅读整篇文章,你完全可以跳过这部分。

Question:什么是领域模型?

为解决场景下的问题而形成的一套模型,然后使用这套模型来解决业务问题。 根据重复劳动经验我们会形成一套模式。领域模型也一样会形成一套模式,他包括:实体、值对象、模块、领域服务。

Question:领域模型是怎么更新到数据库的呢?

使用资源库(repository)将领域模型更新到数据库。 在一个一对多的实体,例如:用户组(Group)和用户(User),用户组内有N个用户, 如果用户非常多,一次加载Group肯定会造成性能损失,这种问题怎么设计呢? 如果不使用领域模型依靠经验你会想到拆分,现在你使用了领域模型想的方案也应该是拆分。 我看到有些人把repository注入到领域模型内,这种做法是错误的。

Question:领域模型是否要引入一种架构模式?例如CQRS

首先我想说的是领域模型不需要引入架构模式。 领域模式是解决领域内的业务问题的,他不是解决架构问题,所以领域模型本身不需要引入架构。 当你使用领域模型的时候,领域层之上你可以使用架构,比如CQRSMVC等等。


要不,我们开始正文。我想从传统的项目开始讲解一步步的过渡到领域模型。 我将讲解三种组织代码的结构,分别是:传统模式、IDDD模式、我思考的模式。

说一下我们用到的技术框架:

  • ORM:Spring Data JPA
  • Database:h2-database

我们先假设一个需求用例,现在我们要开发一个身份认证模块(identity)其中包括的功能有 获得用户信息、修改密码、用户认证。

使用传统项目来开发整个需求

首先来看下我们的项目结构:

b7a547934fec395a7ed8748121f70ef6.png

这个项目结构大家已经非常熟悉了,就是我们传统的分层方式。 我们通常会把业务逻辑写在service里面,如下:

79032d97a93395085ed831488a22a1c5.png

整个功能我们已经开发完了,是不是看着非常简单。 我们来看changePassword方法,我们通过repository根据用户名获得到用户, 然后调用authenticate方法进行认证,认证通过后修改密码(user.setPassword())。 是不是看上去没有任何毛病,而且程序还运行的非常成功。嗯,确实是。 但是在这种编程模式里我们更多的是从数据库的模式来开发的,因为User只是封装了静态数据。 然后在service中来完成修改密码这个逻辑,这种操作更像是过程化编程。

我们应该从面向对象的角度来思考问题。 一提到对象你首先想到的是什么?继承?封装?多态?还有吗? 我再添一条类是一组相关的属性和行为的集合

既然我提到了属性和行为,那我们重新思考下修改密码这个用例: 首先passwordUser类上的一个属性,对于修改密码我们应该是调用User对象上的changePassword方法, 然后由changePassword来完成修改password属性,这就是封装。

接下来我们使用领域模型再来完成上面用例的业务。

使用IDDD来开发整个需求

首先我们也是来看一下IDDD的项目结构:

6a7d1db2c1341286d1a3137eb10dc347.png

当你看到这个项目结构的时候,你可能心生疑惑:“怎么没有service, repository这样的包呢?”

我来告诉你,IDDD推荐我们使用应用层、领域层和基础设施层来做分层。 对于这种分包方式是《实现领域驱动设计》这本书比较推荐的。所以这个项目我们以这种方式来组织我们的代码。

接下来我们来看看应用层服务和领域模型:

bfabf2543bde410c2b38a15e3ea27c59.png

36de0a9c81ac81e7a1ff55a0b180d679.png

再来看UserService上的changePassword方法,我们还是通过authenticate获得用户, 然后又调用了用户的changePassword来修改密码。

但是你会发现我们并没有把密码加密这个交由User来完成,这是为什么呢?

因为加密不是User的职责。就像authenticate一样,你自己不可能认证自己, 就像你不借助镜子永远不会看清你的脸蛋。就像你会问别人我今天漂不漂亮,而不会自欺欺人的告诉自己我很漂亮。

通过将changePassword交由User,你会发现你的业务很清晰了。 因为你对号入座将原本由用户该做的事情又还给了用户。

接下来我想说一个我认为的分层架构,以及如何组织代码。这部分知识涉及到了UML、面向对象。

我直接上图,然后在细细讨论:

b15d9976c1c7454992bf0e9281af7661.png

当你看到这个结构,你会发现怎么没有层了呢?怎么都放在了一个包里。 聊到这我就应该给你说一说UML中的模块和构造型。 我们都已经很熟悉模块了,因为我们平常都是在用包来组织模块。 这个我就不多讲了,我想说的什么是构造型。构造型就是用来区分不同种类的类。 玩了那么多年的Spring,还记得那几个常用的组件注解(@Component@Controller@Service@Repository)吗? 他们被放置在org.springframework.stereotype这个包下,就是为了区分你的不同种类的类。

所以我们现在为我们的模块(identity)画一个UML的类图:

f7813f92bac83e50a30d7587c73c4878.png

430a2d96734524862c19e3d1d8f15984.png

当你看到UML的类图再和刚才的Java项目结构图进行对比是不是有些清晰了呢? 这个时候你可以再配合一个用例和时序图,来表达你的业务。

40b3f505fe06a2acaddff09a201b231f.png

整个示例源码

what-is-a-domain-model-example

结束

也大体说完了整个演变过程,这也是我一年了的技术总结吧。

为了搞清楚心中的一个疑惑:“为什么我们项目的代码组织结构和国外开源框架的组织结构有那么大的不同呢。” 我花了一年的时间看完了:《领域驱动设计》、《实现领域驱动设计》、 《企业应用架构模式》、《软件建模与设计》这几本书,其实还有正在看没有看完的。

当你想搞懂一个东西的时候,你应该把他搞到通透,然后再说你怎么看待这个问题。 有的时候我在看完DDD以后,我还是会问自己,这是我想要的吗?出现这种疑惑还是需要攀登, 你应该继续选择研究这本书引用其他知识,知识的传播可能是书籍也可能是论文。 当把这些迭代的思想看完以后,你还得回过头来在看这个问题,再去揣摩。可能会有新的突破。 只有这样一次次的突破,才能解决你心中的疑惑。

还有很多细节我可能没有一一表达出来。 上述演变过程仅代表我个人思考,禁止转载,如有误人子弟之处,请您指出。

如有问题请加QQ群讨论:

4affb52139467608937a09aa8e7ddb94.png

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

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

相关文章

Android四级缓存,RecyclerView 源码四级缓存原理

入口我们从使用功能上去读取源码,通常的用法是这个样子-> 我们设置layoutmanager,GridLayouManager 继承LinearLayoutManager,所以我们就LinearLayoutManager 为基准查看rv.layoutManager GridLayoutManager(this,5)rv.addItemDecoration…

织梦自定义html文本,织梦自定义标签dede:sql根据自定义字段填的文章id获取相关文章...

这篇文章主要为大家详细介绍了织梦自定义标签dede:sql根据自定义字段填的文章id获取相关文章,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,有需要的朋友可以收藏方便以后借鉴。有的时候我们需要通过织梦的dede:sql据自定义字段填的文章id获取相关文…

python 杀死子进程_Python:当父异常终止时,如何杀死子进程?

小编典典 呵呵,我昨天自己在研究这个!假设您无法更改子程序: 在Linux上,prctl(PR_SET_PDEATHSIG,...)可能是唯一可靠的选择。(如果绝对有必要终止子进程,那么您可能希望将终止信号设置为SIGKILL而不是SIGTE…

html评论置顶功能,微信公众号精选留言评论怎么置顶显示?功能在哪里设置?...

微信公众号精选留言怎么置顶?微信公众号留言功能新增了置顶精选留言的设置,那么微信公众号留言功能在哪里设置呢?下文小乐哥给大家介绍一下!微信公众号精选留言怎么置顶?微信公众平台悄然上线了一个新功能,…

python函数增强代码可读性_写Python必须知道的这几个代码技巧!你会吗?

Day09 函数的初始 函数:函数是以功能为导向,一个函数封装一个功能。登录,注册,文件的改的操作。。。 函数减少代码的重复性,增强了代码的可读性; 获取任意一个字符串的元素的个数 s1 "xiaomingxiaoho…

shell脚本发邮件内容html,[转]Shell脚本中发送html邮件的方法

作为运维人员,免不了要编写一些监控脚本,并将监控结果及时的发送出来。那么通过邮件发送是比较常用的一种通知方式了。通常的,如果需要发送的内容是简单的文本文件,那么使用/bin/mailx就可以了,但是如果想要发送更复杂…

learn python app v3_‎App Store 上的“Learn Python and Scratch”

Learn “Python and Scratch Programming” from AI driven coach and satisfy your thirst for knowledge. App offers bite sized videos, quizzes and AI driven coach to help you become smarter and become great. Just 60 minutes a week can help you become great in …

计算机应用基础知识竞赛题,计算机基础知识题库

随着科学技术的进步,计算机已逐渐渗入人们的生活中,相应的计算机知识是需要具备的,那么你对计算机基础知识了解多少呢?以下是由学习啦小编整理关于计算机基础知识题库的内容,希望大家喜欢!计算机基础知识题库一、单选题1、 第一台…

inspect python_python之inspect模块

inspect模块主要提供了四种用处: 1.对是否是模块、框架、函数进行类型检查 2.获取源码 3.获取类或者函数的参数信息 4.解析堆栈 一、type and members 1. inspect.getmembers(object[, predicate]) 第二个参数通常可以根据需要调用如下16个方法; 返回值为…

HTML打开网页拒绝访问,192.168.1.1拒绝访问怎么办?

问:为什么设置路由器时,在浏览器中输入192.168.1.1,结果显示拒绝访问,这个问题怎么解决?答:如果是在设置路由器的时候,登录192.168.1.1被拒绝访问,多半是你自己操作有问题导致的&…

python中goto的用法_python3里用goto

python里用goto也是小Pa最近做的项目里的一个需求。python不像C有自带的goto, 需要用额外的包,目前为止,小pa只看到2个goto的包: 这2个小Pa都下载试用过,goto因为开发的时候比较早,对于python3的支持不太好,不推荐使用…

delphi打印html文件路径,Delphi获取文件名、不带扩展名文件名、文件所在路径、上级文件夹路径的方法...

1.获取不带扩展名的文件名方法,利用ChangeFileExt函数修改传入参数的扩展为空,并不会对文件本身产生变更。ChangeFileExt(ExtractFileName(‘D:\KK\Test\123.txt‘),‘‘); //返回 1232.获取上级文件夹路径的方法。ExtractFileDir(‘D:\KK\Test\‘)‘..‘…

gitlab git clone 输入密码_gitlab1:部署gitlab

1、配置yum源vim /etc/yum.repos.d/gitlab-ce.repo复制以下内容:[gitlab-ce]nameGitlab CE Repositorybaseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/gpgcheck0enabled12、更新本地yum缓存sudo yum makecache3、安装GitLab社区版sudo y…

计算机专业英语第五章ppt,计算机专业英语第五章.ppt

计算机专业英语第五章Background The Internet protocols are the worlds most popular open-system (nonproprietary) protocol suite because they can be used to communicate across any set of interconnected networks and are equally well suited for LAN and WAN comm…

python播放在线音乐_Python实现在线音乐播放器

最近这几天,学习了一下python,对于爬虫比较感兴趣,就做了一个简单的爬虫项目,使用Python的库Tkinsert做了一个界面,感觉这个库使用起来还是挺方便的,音乐的数据来自网易云音乐的一个接口,通过re…

golang如何打印float64的整数部分_2020-08-10:如何不用加减乘除求浮点数的2倍值?...

福哥答案2020-08-10:浮点数符号位阶码尾数,阶码加1就是浮点数的2倍值。代码用golang编写,如下:package test33_addimport ( "fmt" "math" "testing")/*//https://www.bbsmax.com/A/6pdDX7…

五年级数学上册用计算机探索规律,人教版小学五年级数学上册《用计算器探索规律》课后反思...

当前,新课程改革强调学生学习方式的转变.高效课堂是课程改革过程中有效学习方式之一.在高效课堂中,孩子们能发挥自己潜能、展示自己的才能,提高了孩子们的学习兴趣.如何让高效课堂焕发光彩能?一、合理分组,恰当分工合理分组是高效课堂顺利进行的前提.在以前的学习过…

mysql varchar 非空判断_工资从1万到3万,你还差mysql数据库优化之系列三

查询性能的优化优化查询分析的步骤:1.应用查询是否检索超过需要的数据2.mysql服务器是否在分析超过需要的数据正确使用索引:1.like语句操作一般不使用%或_开头例如: select * from tableName where name like %cn;只能使用like aaa%;2.组合索引例如索引index index_name (a, b,…

etl数据抽取工具_数据同步工具ETL、ELT傻傻分不清楚?3分钟看懂两者区别

什么是数据同步工具(ETL、ELT)数据同步工具ETL或者ELT的作用是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程,目的是将企业中的分散、零乱、标准不统一的数据整合到一起,为企业的决策提供分析依据。数据同步是大数据项目重要的一个环节。…

浙江等高等学校计算机,2010年浙江省高等学校计算机等级考试

2010年上半年浙江省高等学校计算机等级考试二级C程序设计试卷一、程序阅读与填空(24小题,每小题3分同,共72分)1.阅读下列程序说明和程序,在每小题提供的若干可选答案中,挑选一个正确答案。【程序说明】输入一个正整数&…