切换导航
首页
技术问答
编程语言
前端开发
移动开发
开发工具
程序设计
行业应用
CMS系统
服务器
频道导航
▸ PHP
▸ Java
▸ Java SE
▸ Python
▸ C#
▸ C&C++
▸ Ruby
▸ VB
▸ asp.Net
▸ Go
▸ Perl
▸ netty
▸ Django
▸ Delphi
▸ Jsp
▸ .NET Core
▸ Spring
▸ Flask
▸ Springboot
▸ SpringMVC
▸ Lua
▸ Laravel
▸ Mybatis
▸ Asp
▸ Groovy
▸ ThinkPHP
▸ Yii
▸ swoole
▸ HTML
▸ HTML5
▸ JavaScript
▸ CSS
▸ jQuery
▸ Bootstrap
▸ Angularjs
▸ TypeScript
▸ Vue
▸ Dojo
▸ Json
▸ Electron
▸ Node.js
▸ extjs
▸ Express
▸ XML
▸ ES6
▸ Ajax
▸ Flash
▸ Unity
▸ React
▸ Flex
▸ Ant Design
▸ Web前端
▸ 微信小程序
▸ 微信公众号
▸ iOS
▸ Android
▸ Swift
▸ Hybrid
▸ Cocos2d-x
▸ Flutter
▸ Xcode
▸ Silverlight
▸ cocoa
▸ Cordova
前端之家
设计模式
领域驱动设计(DDD)学习成果精简总结
领域驱动设计(DDD)学习成果精简总结
2020-02-23
设计模式
前端之家
前端之家
收集整理的这篇文章主要介绍了
领域驱动设计(DDD)学习成果精简总结
,
前端之家
小编觉得挺不错的,现在分享给大家,也给大家做个参考。
领域驱动设计(DDD)学习成果精简总结
2011年12月03日 14:44
DDD领域驱动设计
20
顶一下
1. 创建领域对象采用构造
函数
或者工厂,如果用工厂时需要依赖于领域服务或仓储,则通过构造
函数
注入到工厂;
2. 一个聚合是由一些列相联的Entity和Value Object组成,一个聚合有一个聚合根,聚合根是Entity,整个聚合被看成是一个数据
修改
的单元,也就是说整个聚合内的所有对象要么同时被保存,要么都不能保存,即保存到数据持久层时必须以覆盖的方式来保存,而不是追加方式或合并的方式来保存,否则无法确保聚合内的对象的数据一致性。作为推导的一个结论:我们不能只保存一个聚合内的一部分对象;聚合内的所有实体和值对象应该总是一起被取出来一起被保存,因为一个聚合是一个数据持久化的单元,不需要考虑将整个聚合根取出来有
性能
问题,因为任何一个聚合根都有明确的边界。目前的内存
缓存
框架都已发展的比较成熟,
性能
已经不是问题;如MongoDb,MemCache,No
sql
,等等;
3. 聚合内的对象之所以聚合在一起的关键原因不是因为它们具有一些关联关系或依赖关系,而是因为聚合内的对象之间具有某些不变性规则,在任何时候,聚合内的所有这些对象必须满足这些不变性规则。所以,如果一些对象之间看似有一些关联关系或依赖关系,但是他们之间不具有任何不变性约束,那么就不应该把这些对象放在一个聚合中,否则只是
增加
对象之间不必要的耦合性,
增加
对象维护的难度;
4. 所谓的不变性约束是指:假设有一个采购订单Order,一个Order下有多个订单项OrderItem,假设有一个约束是,该采购订单的总额不能超过100元。那么订单的总额不能超过100元就是一个不变性约束;那么Order和OrderItem聚合在一起就显得很有意义。在这种情况下,有Order来维护这个规则,当整个订单被保存时,比如采用覆盖的方式保存到
数据库
。再举个例子,比如一个论坛中有帖子和
回复
,大家都知道一个帖子有多个
回复
,
回复
离开帖子没有意义。所以大家很自然会认为帖子和
回复
应该在一个聚合内,帖子是聚合根。但是这样其实很有问题,因为你仔细想想会发现帖子和
回复
之间没有不变性约束规则,
回复
和帖子之间只有一个简单的1:N的关系而已。如果每次在
添加
一个
回复
时,都把帖子先取出来,然后再帖子的
回复
列表中把新的
回复
添加
进去,然后再保存整个帖子,那么不难想想,在多
用户
并发回同一个帖子的时候一定会造成帖子不能保存的情况,因为在保存帖子时是采用覆盖的方式,但是发现别人已经回帖了。所以不能覆盖,如果继续覆盖不管的话,那就会导致在你之前别人的
回复
会被冲掉;实际上仔细分析一下,帖子和
回复
都应该是聚合,并且分别都是聚合根,我们要确保的仅仅是
回复
的帖子不能被
修改
即可。
添加
一个
回复
实际上和帖子无关,帖子根本不关心已经有多少个
回复
了。这点和之前的订单的例子不同,订单需要准确维护其包含的所有订单项以便能够计算出总价是否超出100元。其实这么多问题还是不足以详细说明什么样的对象该被聚合在一起,这里只是作为抛砖引玉,引发大家思考如何设计聚合。
5. Evans关于聚合的两条推荐准则:1)聚合不要设计的过大,过大的聚合很难确保不变性,从而很难确保数据的强一致性;2)聚合与聚合之间不要通过引用的方式来关联,而应该通过ID关联,通过ID关联也同样能表示聚合之间的关系,并且具有更好的
性能
和可
伸缩性
,聚合根之间通过ID关联的好处是:不会因为Load一个聚合根而把其他关联的聚合根一起Load出来,这样也避免了Load一个聚合根会把整个
数据库
Load出来的风险;另外,对ORM的要求也很低,不需要ORM
支持
LazyLoad;聚合根与聚合根之间的关系不像聚合内的Entity之间这么强烈内聚,它们之间仅仅是某种比较弱的关联关系,每个聚合根都有其独立的生命周期;
6. 聚合内的非跟的Entity以及Value Object之间不要相互引用,聚合内的所有Child可以对根Entity持有引用,如果一个Child Entity需要和另外一个Child Entity交互,则因该通过聚合根完成;
7. 我们应该尽量减少聚合之间关联,尽量做到单向关联,只保留确实需要处理的经常需要用到的遍历方向的关联;
8. 仓储应理解为一个在内存中维护一系列聚合根的集合;
9. 一个聚合根配备一个仓储;
10.仓储提供的接口应该总是接受聚合根或返回聚合根,不能返回聚合内的其他Entity或Value Object;
11.不要把仓储理解为DAO,仓储属于领域模型的一部分,代表了领域模型向外提供接口的一部分,而DAO是表示
数据库
向上层提供的接口表示;
12.仓储的目的不是为了
支持
界面
查询
,不要给仓储中设计一些目的是为了为界面提供
显示
数据的接口,仓储提供的所有接口应该仅为领域模型使用;基本的仓储接口只需要三个:Add,Remove,GetById,其他的扩展接口可以根据业务需要扩展接口声明;
13.如果一个操作仅由一个聚合根就可以完成,那么直接
调用
该聚合根完成即可;
14.领域服务表示领域模型中的一些业务操作,这些操作通常由多个聚合根或仓储或其他领域服务相互协作完成,那么需要为这些操作建立领域服务,在领域服务中以过程化的方式来一步步首先根据各个聚合的ID
获取
到操作的相关聚合根,然后
调用
聚合根完成整个业务操作;比如资金转帐,这是经典的领域服务的例子;再比如在
调用
某个聚合根做一个数据更新之前需要先判断一些业务规则,但是这些判断规则不能在该聚合根内做,因为这样做可能会导致聚合根依赖于外部的领域服务或仓储,此时,应该交给领域服务来完成规则校验和聚合根数据更新的整个过程。领域服务可以依赖仓储或聚合根;
15.领域服务依赖仓储时,工厂依赖于领域服务或仓储时,都因该采用构造
函数
注入的方式,这样可以避免领域模型中不会出现DependencyResolver.Resolve<T>()这样的语句;
16.切忌不要因为领域服务的引入让聚合根变得贫血,聚合根应该有的职责还是必须要由聚合根来承担;
17.聚合根内不要依赖领域服务或仓储,如果你发现一个聚合根的职责需要依赖于某个领域服务或仓储来帮忙完成一些其他的逻辑(像判断业务规则之类),那么通常你要考虑这个职责不应该由该聚合根来承担,而应该建立合适的领域服务来承担;聚合根的主要职责是管理其内聚的所有Child Entity或Value Object的业务完整性;
18.领域驱动设计时,为对象分配职责时,可以参考信息专家模式:将职责分配给拥有执行该职责所需信息的人;如果一个聚合根看起来拥有执行某个职责所需的信息,但没包含全部所需信息,此时则不应该将该职责分配给该聚合根,因为强行分配给它,会导致该聚合根没有内聚性,因为势必会依赖于其它的领域对象或领域服务或仓储;
19.要学习CQRS架构,要知道我们应该将应用程序的业务逻辑处理部分(即
用户
命令响应部分)和
查询
部分分离;我们应该用两个不同的技术来实现这两个部分的实现;用
DDD
领域模型来实现命令部分;用最快的
查询
引擎来实现
查询
部分; 20.如果要采用CQRS架构,我们需要考虑一个成熟可靠的底层框架,否则很容易导致命令端产生的领域对象的状态无法同步(后者丢失)到
查询
端的存储中; 21.领域对象上的
属性
可以具有get和set,因为我们平时所理解的对象不是真正的对象,而是某个事实的描述,比如图书管理系统中的一个Book对象,表示图书管中放着一本书,然后该书可能有一个入库时间。现实生活正的话,书本的入库时间绝对不可能变化,但是软件中的Book因为不是真正的现实生活中的书本,而只是表示图书馆中有一本书这个事实的描述,我们当然可以
修改
这个事实,因为我们可能因为之前在书本入库时所输入的入库时间是错的,需要
修改
该入库时间,此时就有提供set的必要了。所以,理论上任何一个Entity,除了ID之外,其他所有
属性
都可以更改,因为这些
属性
并不表示现实生活中的真正对象的特征,而仅仅只是对一个事实的描述;刚开始Book对象对书本入库这个事实的描述可能有问题,此时我们就需要
修改
该Book的
属性
;我想这个例子已经充分说明为什么可以提供get和set了; 22.不要总是零散的不加任何分组的设计Entity的
属性
,因为有些
属性
在逻辑上或业务上就是内聚的,代表一个完整的概念,比如Country,Province,City,Town,Street,等这些
属性
表示一个地址的信息,此时我们应该设计一个Address对象来表示该地址信息,此时该Address就是一个值对象。所以我们在设计Entity的
属性
时,要好好想想,哪些子
属性
其实在业务上是一个完整的概念,此时我们就需要考虑将这些相关的
属性
设计为一个值对象; 23.切忌值对象必须是只读的,值对象之所以叫值对象最主要的是因为它表示一个值,而不是一个对象;值是不会变化的,是一个明确含义的不变的事物,比如3表示一个值,表述
数量
是3,3永远不能变化;所以说,世界之所以存在,是因为有这些永恒不变的值对象的存在;我们只要把值对象理解为3,“abcd”这样的永恒不变的值就行了; 24.不要让领域模型去模拟现实,模拟
用户
(软件使用者)与领域模型交互的过程;领域模型要实现的应该是
用户
的需求,领域模型中不应该包含
用户
的成分,想想只有空杯子才能装水的道理,即无为以之用的道理就明白了;所以,我们在设计领域模型时首先要明白领域模型要完成的事情是什么;这方面,多看看用例图,就知道软件该做的事情了,推荐大家看的书是:Craig Larman写的《UML和模式应用》一书,非常经典; 25.是该学习一下什么是强一致性,什么是最终一致性的时候了,必须了解什么是CAP定理;
上一篇:软件测试杂谈
下一篇:《com原理与应用》第4章聚合示例程
猜你在找的设计模式相关文章
适配器模式-让不兼容的接口得以适配
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合...
作者:前端之家 时间:2021-02-24
策略模式-定义一个算法族
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独...
作者:前端之家 时间:2021-02-24
设计模式之高质量代码
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的...
作者:前端之家 时间:2021-02-24
模板方法模式-封装一套算法流程
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在...
作者:前端之家 时间:2021-02-24
迭代器模式-统一集合的遍历方式
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
作者:前端之家 时间:2021-02-24
单例模式的五种实现方式及优缺点
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
作者:前端之家 时间:2021-02-24
组合模式-统一的处理个别对象与组合对象
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方...
作者:前端之家 时间:2021-02-24
装饰者模式-动态的包装原有对象的行为
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
作者:前端之家 时间:2021-02-24
观察者模式-将消息通知给观察者
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候...
作者:前端之家 时间:2021-02-24
代理模式-访问对象的代理而非其本身
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下...
作者:前端之家 时间:2021-02-24
编程分类
算法
设计模式
多媒体技术
正则表达式
Elasticsearch
Flink
Hadoop
IDE
最新文章
• 适配器模式-让不兼容的接口
• 策略模式-定义一个算法族
• 设计模式之高质量代码
• 模板方法模式-封装一套算法
• 迭代器模式-统一集合的遍历
• 外观模式-简化子系统的复杂
• 单例模式的五种实现方式及
• 组合模式-统一的处理个别对
• 装饰者模式-动态的包装原有
• 观察者模式-将消息通知给观
热门标签
更多 ►
受约束
摘*
day25
Java常用类库
置信
lamda
留存
持续录入
年后
正则表达式30
3.17
regularexpre
匹
多模
适
20130322
基础理论
pathmunge
涵义
reec
tok
需要转义的特
资源分享
validationex
简明魔法
里弄
形如
源码实现
完备
actionscript