DDD设计概念汇总
Posted 流浪少年的梦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DDD设计概念汇总相关的知识,希望对你有一定的参考价值。
文章目录
DDD设计概念汇总
1. 聚合根
对领域概念做静态建模的时候都一类概念被视为聚合根(root), 他有自己的生灭过程, 数据和行为聚合于其上面, 聚合根中有一个唯一的ID可以表征自己并且可以索引到自己的数据.
Aggregate(聚合)是一组相关对象的集合,作为一个整体被外界访问,聚合根(Aggregate Root)是这个聚合的根节点。
聚合由根实体,值对象和实体组成。
聚合根表征的是一个实体, 但是并不是所有的实体都应该抽线成为聚合根, 有些时候应该抽象为注入的数据或者是待处理的消息.
聚合根可以多种类型, 且之间可以构成层级关系(或者其他关系, 网状或者其他, 但是层级关系最自然).
每个聚合根上可以有自己的数据(data)和行为(behavior)。
比如国家的数据可以有土地矿藏人口GDP法律,个人的数据可以有年龄技能收入房产等等。国家的行为可以有改变利率出台政策禁止某种产业,个人行为可以有就业辞职买房结婚等等。林林总总的数据和行为必须是为某个特定领域服务的,总是先抽象出聚合根再将各种领域知识/术语聚合于其上。如果大部分概念可以找到一个合适的聚合根,且聚合根之间关系又是尽量简单的,这个描述就可能还不错。比如上述国家经济模型描述,聚合根之间关系比较复杂,因此未必是一个好的抽象。关键是也没有明确这个系统或领域存在的目的(比如分析央行利率是否需要变动,或者获取投资建议)。
目的不同,建模抽取的聚合根必然不同。建立好的模型的根本是对系统的充分理解。
虽说认识是一步步深入的,但系统设计要在聚合根抽取这个层面反复的话,比如做了三个月, 聚合根模型变了,这可能还是灾难性的。因此可以先抽取显而易见的,其它晦涩不定的,需要延迟决策。
有了聚合根,我们应当避免创造上帝类(或超长函数)。而是将聚合根上的数据和行为分类组织,在不同的场景,聚合根参与不同的过程,表现出不同的行为,承担不同的角色。
聚合根上只有data和behavior,这种拆分(或者组织)往往不能找到单一职责的边界,behavior和data仍然可能实现的非常复杂。这种复杂度有可能来源于聚合根所描述实体本身状态(status)的复杂。这个时候,status作为一类特殊的数据,应该被升格成需要单独描述的聚合物。并且behavior和data的拆分需要依赖不同status,简单的说,root参与的过程有若干不同的抽象行为(abstract behavior)组合而成,每个abstract behavior依赖status可以选择不同的实现(implements)。业务处理过程,行为选择过程,行为的具体实现,这三者应该被单独描述(同时它们的变化周期也不相同),这样系统的复杂度才可能被有效降解。至于没用状态的过程,比如数字信号处理,它是严格被算法和公式约束的,其实现难度往往不来自于概念抽取和复杂关系上。
2. 如何判断标记领域
所谓的领域还是业务合集, 本质还说数据, 标记一个领域其实就是进行控制数据访问. 本领域内的数据和表必须通过这个领域来实现数据访问, 不能直接跨过我访问我内部的数据.
3. 如何创建好的聚合?
- 边界内的内容具有一致性:在一个事务中只修改一个聚合实例。如果你发现边界内很难接受强一致,不管是出于性能或产品需求的考虑,应该考虑剥离出独立的聚合,采用最终一致的方式。
- 设计小聚合:大部分的聚合都可以只包含根实体,而无需包含其他实体。即使一定要包含,可以考虑将其创建为值对象。
- 通过唯一标识来引用其他聚合或实体:当存在对象之间的关联时,建议引用其唯一标识而非引用其整体对象。如果是外部上下文中的实体,引用其唯一标识或将需要的属性构造值对象。
如果聚合创建复杂,推荐使用工厂方法来屏蔽内部复杂的创建逻辑。
聚合内部多个组成对象的关系可以用来指导数据库创建,但不可避免存在一定的抗阻。如聚合中存在List<值对象>,那么在数据库中建立1:N的关联需要将值对象单独建表,此时是有ID的,建议不要将该ID暴露到资源库外部,对外隐蔽。
4. 实体
当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)。
例:最简单的,公安系统的身份信息录入,对于人的模拟,即认为是实体,因为每个人是独一无二的,且其具有唯一标识(如公安系统分发的身份证号码)。
5. 值对象
当一个对象用于对事务进行描述而没有唯一标识时,它被称作值对象(Value Object)。
例:比如颜色信息,我们只需要知道{“name”:“黑色”,“css”:"#000000"}这样的值信息就能够满足要求了,这避免了我们对标识追踪带来的系统复杂性。
值对象很重要,在习惯了使用数据库的数据建模后,很容易将所有对象看作实体。使用值对象,可以更好地做系统优化、精简设计。
它具有不变性、相等性和可替换性。
在实践中,需要保证值对象创建后就不能被修改,即不允许外部再修改其属性。在不同上下文集成时,会出现模型概念的公用,如商品模型会存在于电商的各个上下文中。在订单上下文中如果你只关注下单时商品信息快照,那么将商品对象视为值对象是很好的选择。
PS : 谨慎使用值对象
在实践中,我们发现虽然一些领域对象符合值对象的概念,但是随着业务的变动,很多原有的定义会发生变更,值对象可能需要在业务意义具有唯一标识,而对这类值对象的重构往往需要较高成本。因此, 在特定的情况下,我们也要根据实际情况来权衡领域对象的选型。
6. 界限上下文
一个由显示边界限定的特定职责。领域模型便存在于这个边界之内。在边界内,每一个模型概念,包括它的属性和操作,都具有特殊的含义。
一个给定的业务领域会包含多个限界上下文,想与一个限界上下文沟通,则需要通过显示边界进行通信。系统通过确定的限界上下文来进行解耦,而每一个上下文内部紧密组织,职责明确,具有较高的内聚性。
一个很形象的隐喻:细胞质所以能够存在,是因为细胞膜限定了什么在细胞内,什么在细胞外,并且确定了什么物质可以通过细胞膜。
7. 限界上下文之间的映射关系
- 合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
- 共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
- 客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
- 遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
- 防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
- 开放主机服务(Open Host Service):定义一种协议来让其他上下文来对本上下文进行访问。
- 发布语言(Published Language):通常与OHS一起使用,用于定义开放主机的协议。
- 大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
- 另谋他路(SeparateWay):两个完全没有任何联系的上下文。
8. 领域服务
一些重要的领域行为或操作,可以归类为领域服务。它既不是实体,也不是值对象的范畴。
当我们采用了微服务架构风格,一切领域逻辑的对外暴露均需要通过领域服务来进行。
如原本由聚合根暴露的业务逻辑也需要依托于领域服务。
9. 领域事件
领域事件是对领域内发生的活动进行的建模。
10. 术语
PS : 合作关系(PartnerShip)
ACL : 防腐层(Anticorruption Layer)
DC : 数据耦合(Data Coupling)
OHS : 开放主机服务(Open Host Service)
11. DDD的战略建模与战术建模
战略建模-Strategic Modeling:
- 限界上下文(Bounded Context)
- 上下文映射图(Context Mapping)
战术建模-Tactical Modeling:
- 聚合-Aggregate
- 实体-Entity
- 值对象-Value Objects
- 资源库-Repository
- 领域服务-Domain Services
- 领域事件-Domain Events
- 模块-Modules
以上是关于DDD设计概念汇总的主要内容,如果未能解决你的问题,请参考以下文章