DDD(Domain-Driven Design) 领域驱动设计
DDD(Domain-Driven Design) 领域驱动设计
1. DDD(Domain-Driven Design)是什么?
DDD是Eric Evans在2003年出版的《领域驱动设计:软件核心复杂性应对之道》(Domain-Driven Design: Tackling Complexity in the Heart
of Software)一书中提出的具有划时代意义的重要概念。
Domain-Driven Design 是指通过统一语言、业务抽象、领域划分和领域建模等一系列手段来控制软件复杂度的方法论。
DDD 的革命性在于领域驱动设计是面向对象分析的方法论,它可以利用面向对象的特性有效化解复杂性。
2. 数据驱动和领域驱动
2.1 数据驱动
目前的主流开发模式是数据驱动。有了需求先建数据库表,然后编写逻辑。
2.2 领域驱动
领域驱动设计关心的是业务中的领域划分(战略设计)和领域模型(战术设计),其开发过程不再以数据模型为起点,而是以领域模型为出发点。
领域模型对应的是业务实体,在程序中主要表现为类、聚合根和值对象,它更加关注业务语义的显性化表达,而不是数据的存储和数据之间的关系。这是“领域驱动设计”和“数据驱动设计”之间显著的区别。
3. 领域驱动设计优势
1. 统一语言
统一语言(Ubiquitous Language)的主要思想是让应用能和业务相
匹配,这是通过在业务与代码中的技术之间采用共同的语言达成的。
2. 面向对象
DDD的核心是领域模型,这一方法论可以通俗地理解为先找到业务中的领域模型,以领域模型为中心,驱动项目开发。领域模型的设计精髓在于面向对象分析、对事物的抽象能力,一个领域驱动架构师必然是一个面向对象分析的大师。
DDD鼓励我们接触到需求后第一步就是考虑领域模型,而不是将其切割成数据和行,然后用数据库实现数据,用服务实现行为,最后造成需求的首尾分离。DDD会让你首先考虑业务语言,而不是数据。DDD强调业务抽象和面向对象编程,而不是过程式业务逻辑实现。重点不同,导致编程世界观不同。
3. 业务语义显性化
统一语言使得我们的核心领域概念可以无损地在代码中呈现,从而提升代码的可理解性。
4. 分离业务逻辑和技术细节
代码复杂度是由业务复杂度和技术复杂度共同组成的。实践DDD还有一个好处,是让我们有机会分离核心业务逻辑和技术细节,让两个维度的复杂度有机会被解开和分治。
核心业务逻辑是整个应用的核心,最好只是简单Java类。也就是说,核心业务逻辑对技术细节没有任何依赖,依赖都是由外向内的,,即使有由内向外的依赖,也应该通过依赖倒置来反转依赖的方向。
4. 领域驱动设计核心概念
4.1 领域实体
面向对象编程的核心思想,也是DDD中寻找领域实体的核心思想。
领域实体其实就是对象。
4.2 聚合根
聚合根(Aggregate Root)是DDD中的一个概念,是一种更大范围的封装,会把一组有相同生命周期、在业务上不可分割的实体和值对象放在一起,只有根实体可以对外暴露引用,这也是一种内聚性的表现。
确定聚合边界要满足固定规则(Invariant),是指在数据变化时必须保持的一致性规则,具体规则如下:
- 根实体具有全局标识,最终负责检查规定规则
- 聚合内的实体(领域实体)具有本地标识,这些标识在Aggregate内部才是唯一的
- 外部对象不能引用除根Entity之外的任何内部对象
- 只有Aggregate的根Entity才能直接通过数据库查询获取,其他对象必须通过遍历关联来发现。
- Aggegate内部的对象可以保持对其他Aggregate根的引用。
- Aggregate边界内的任何对象在修改时,整个Aggregate的所有固定规则都必须满足。
4.3 领域服务
有些领域中的动作是一些动词,看上去并不属于任何对象。它们代表了领域中的一个重要的行为。当这样的行为从领域中被识别出来时,推荐的实践方式是将它声明成一个服务。其作用仅仅是为领域提供相应的功能。
识别领域服务,主要看它是否满足以下3个特征。
- 服务执行的操作代表了一个领域概念,这个领域概念无法自然地隶属于一个实体或者值对象。
- 被执行的操作涉及领域中的其他对象。
- 操作是无状态的(无状态即没有保存数据)。
4.4 领域事件
领域事件(Domain Event)是在一个特定领域由一个用户动作触发的,是发生在过去的行为产生的事件,而这个事件是系统中的其他部分或者关联系统感兴趣的。
1.事件命名
事件是表示发生在过去的事情,所以在命名上推荐使用DomainName + 动词的过去式 + Event
,这样可以更准确地表达业务语义。
2.事件内容
事件内容在计算机术语中叫作payload
,有以下两种形式:
(1)自恰(Enrichment):就是在事件的payload中尽量多放数据,这样consumer不需要回查就能处理消息,也就是自恰地处理消息。
(2)回查(Query-Back):这种方式是只在payload放置id属性,然后consumer通过回调的形式获取更多数据。这种形式会加重系统的负载,可能会引起性能问题。
4.5 边界上下文
领域实体的意义是有上下文的。边界上下文(Bounded Context)的作用是限定模型的应用范围,在同一个上下文中,要保证模型在逻辑上统一,而不用考虑它是不是适用于边界之外的情况。
那么不同上下文之间的业务实体要如何实现交互呢?
就像关系数据库和对象之间需要ORM一样,不同上下文之间的实体也需要映射。
在DDD中,这种机制叫作上下文映射(Context Mapping),我们可以使用防腐层(Anti-Corruption)来完成映射的工作。
5 领域建模方法
5.1 用例分析法
用例分析法是进行领域建模中最简单可行的方式。步骤如下:
1. 获取用例描述
是一段格式化的需求文字描述。
2. 寻找概念类
寻找概念类就是对获取的用例描述进行语言分析,识别名词和名词短语,将其作为候选的概念类。
3. 添加关联
关联意味着两个模型之间存在语义联系,在用例中的表现通常为两个名词被动词连接起来。
4. 添加属性
我们需要区分概念类和属性(当然名词列表也会有无用的词语)。例如,对于上文抽取到的名词列表,“品名”是“商品”的属性,“iTouch”为无用的词语。
5. 模型精化
模型精化是可选的步骤,有时我们希望在领域模型中表达更多的信息,这时会利用一些新的手段来表达领域模型,包括泛化、组合和子域划分等。
四色建模法
四色建模法源于Peter Coad的Java Modeling In Color With UML一书,它是一种模型的分析和设计方法,要把所有模型分为4种类型,用4种颜色表示。
(1)业务关键时刻(Moment-Interval)
这种对象表示那些在某个时间点存在或者会存在一段时间。这样的对象往往表示了一次外界的请求,比如一次询价(Quotation)、一次下单(Order)或者一次租赁(Rental)。Moment-Interval是最重要的一类对象,是系统的价值所在,一般用粉红色来表示。这样的对象一般有一个起始时间和终止时间,以及一个唯一的标识号,用来唯一地标识这一次客户请求,比如OrderNo。注意,“业务关键时刻”是我给“Moment-Interval”起的中文名称,本来想直译为“时刻-时间段”,但感觉“时刻-时间段”不能体现出这种对象类型的重要性。
(2)角色(Role)
这种对象表示一种角色,往往由人或者物来承担,会有相应的责任和权利。一般,一个Moment-interval对象会关联多个Role。例如,一次下单涉及两个Role,分别是客户(Customer)和商品(Product)。这类对象是除Moment-interval对象之外最重要的一类对象,一般用黄色来表示。
(3)人-事-物(Party,Place or Thing)
这种对象往往表示一种客观存在的事物,例如人、组织、产品或者配件等。
(4)描述(Description)
这种对象一般是用于分类或者描述性的对象,它的属性一般是这一类事物都有的属性,一般用蓝色来表示。
资料
DDD(Domain-Driven Design) 领域驱动设计的更多相关文章
- DDD(Domain Driver Designer) 领域驱动设计简介
领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity i ...
- DDD(Domain Driven Design) 架构设计
一.为什么要分层 分层架构是所有架构的鼻祖,分层的作用就是隔离,不过,我们有时候有个误解,就是把层和程序集对应起来,就比如简单三层架构中,在你的解决方案中,一般会有三个程序集项目:XXUI.dll.X ...
- DDD学习笔录——简介领域驱动设计的实践与原则
DDD在存在许多DDD模式的同时,也有大量实践和指导原则,这些都是DDD思想体系成功的关键. 1.专注于核心领域 DDD强调的是在核心子域付出最多努力的需要.核心子域是你的产品会成功还是会失败的差异化 ...
- csharp: Domain-Driven Design(领域驱动设计)
http://dddsample.sourceforge.net/ https://github.com/citerus/dddsample-core http://dddsamplenet.code ...
- (翻译)领域驱动设计实现-Implementing Domain Driven Design
简介 Implementing Domain Driven Design 领域驱动设计实现 A practical guide for implementing the Domain Driven D ...
- Java开发架构篇《初识领域驱动设计DDD落地》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 DDD(Domain-Driven Design 领域驱动设计)是由Eric Eva ...
- 领域驱动设计(DDD:Domain-Driven Design)
领域驱动设计(DDD:Domain-Driven Design) Eric Evans的"Domain-Driven Design领域驱动设计"简称DDD,Evans DDD是一套 ...
- 领域驱动设计(DDD:Domain-Driven Design) 介绍
Eric Evans的“Domain-Driven Design领域驱动设计”简称DDD,Evans DDD是一套综合软件系统分析和设计的面向对象建模方法,本站Jdon.com是国内公开最早讨论DDD ...
- 领域驱动设计(DDD:Domain-Driven Design) 转摘自:http://www.jdon.com/ddd.html
Eric Evans的“Domain-Driven Design领域驱动设计”简称DDD,Evans DDD是一套综合软件系统分析和设计的面向对象建模方法,本站Jdon.com是国内公开最早讨论DDD ...
随机推荐
- [树]LeetCode589 N叉树的前序遍历
LeetCode N叉树的前序遍历 前言:树的前中后序遍历已经是很经典的题目的,要么递归要么迭代,不过还是比较习惯于递归的写法 TITLE 给定一个 n 叉树的根节点 root ,返回 其节点值的 前 ...
- VuePress 博客之 SEO 优化(一) sitemap 与搜索引擎收录
前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 本篇讲讲 ...
- hive 操作
show databases ;use default;show tables ;create table student(id int, name string) ROW FORMAT DELIMI ...
- Net之线程池的优点
使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及"过度切换".
- [SPDK/NVMe存储技术分析]003 - NVMeDirect论文
说明: 之所以要翻译这篇论文,是因为参考此论文可以很好地理解SPDK/NVMe的设计思想. NVMeDirect: A User-space I/O Framework for Application ...
- bzoj4241/AT1219 历史研究(回滚莫队)
bzoj4241/AT1219 历史研究(回滚莫队) bzoj它爆炸了. luogu 题解时间 我怎么又在做水题. 就是区间带乘数权众数. 经典回滚莫队,一般对于延长区间简单而缩短区间难的莫队题可以考 ...
- CF1225E Rock Is Push (计数)
观察性质计数题orz小贺 考场上跟榜才切 我们只能往下和往右走,那么只有连续的往下和往右可能会造成不合法的情况!如果当前这一步是向右,那么只有它前面连续的一段向右可能影响到它. 考虑把连续的向右/下一 ...
- Java 中用到的线程调度算法是什么?
计算机通常只有一个 CPU,在任意时刻只能执行一条机器指令,每个线程只有获得 CPU 的使用权才能执行指令.所谓多线程的并发运行,其实是指从宏观上看,各个线 程轮流获得 CPU 的使用权,分别执行各自 ...
- OpenSSL实现了5种信息摘要算法有哪些?
OpenSSL实现了5种信息摘要算法,分别是MD2.MD5.MDC2.SHA(SHA1)和RIPEMD.SHA算法事实上包括了SHA和SHA1两种信息摘要算法.此外,OpenSSL还实现了DSS标准中 ...
- 为什么WAIT必须在同步块中
我们知道java的Object有wait和notify方法,如果要使用wait和notify的话,那么必须在synchronized块中,否则会抛出IllegalMonitorStateExcepti ...