架构师篇 DDD领域驱动设计篇2

本文详细解析了DDD架构中的领域划分,包括战略设计(领域、子域、限界上下文)和战术设计(实体、值对象、聚合等),强调了领域模型在微服务设计中的作用,并讨论了实体和值对象的不同形态及适用场景。
摘要由CSDN通过智能技术生成

一 DDD所包含的划分逻辑

1.1 DDD领域划分

在DDD中可以分为战略设计和战术设计,各自包含的内容如下图所示:

1.2 战略设计

战略设计指的是对整个领域进行分析和规划,确定领域中的概念、业务规则和领域边界等基础性问题。在战略设计中,需要对领域进行全面的了解和分析,探究业务的规则和本质,并且需要考虑到领域的未来发展趋势和可能的变化。领域、子域和限界上下文属于战略设计的范畴

 

1.2.1 领域

领域(Domain)其实就是一个组织所要做的整个事情,以及这个事情下所包含的一切内容。这是一个范围概念,而且是面向业务的(注意这里不是面向技术的,更不是面向数据库的持久化)每个组织都有自己的人员、规则和流程,当你为该组织开发软件的时候,你面对的就是这个组织的领域。:知识付费领域

1.2.2 子域

子域是指在一个大的领域中,可以进一步划分出来的独立的业务子领域,它们有着自己的业务概念、规则和流程等。如:子域可以有订阅域、金融域、专栏域等。为了区分重要性的不同,我们又会将子域划分成核心域、通用域以及支撑域。

1.核心域

决定公司和产品核心竞争力的子域就是核心域,它是业务成功的主要因素。核心域直接对业务产生价值。例如,在“RabbitAdvisors”中,订阅域就是核心域。

2.通用域

没有太多个性化的诉求,同时被多个子域使用的、具有通用功能的子域就是通用域。通用域间接对业务产生价值。例如,在“RabbitAdvisors”中,权限域、登录域就是通用域。

3.支撑域

支撑其他领域业务,具有企业特性,但不具有通用性。支撑域间接对业务产生价值,例如,在“RabbitAdvisors”中,专栏域、评论域就是支撑域。

1.2.3 限界上下文*

限界上下文就是业务边界的划分,这个边界可以是一个子域或者多个子域的集合。如何进行划分,一个行之有效的方法是一个界限上下文必须支持一个完整的业务流程,保证这个业务流程所涉及的领域都在一个限界上下文中。限界上下文是微服务拆分的依据,即每个限界上下文对应一个微服务。例如,在“RabbitAdvisors”中,可以有一个限界上下文叫“专栏订阅上下文”,它就包含了订单域和订阅域。

1.3 战术设计

1.3.1 战术设计概述

战术设计则是在战略设计的基础上,对领域中的具体问题进行具体的解决方案设计。战术设计关注的是领域中的具体情境和场景,需要针对具体的问题进行具体的分析和设计,以满足业务需求。实体、值对象、聚合、工厂、资源库、领域服务和领域事件就属于战术设计的范畴。

1.3.2 实体

1.3.2.1 实体的概念

定义:实体是拥有唯一标识和状态,且具有生命周期的业务对象。实体通常代表着现实世界中的某个概念,实体与领域模型密切相关,它是领域模型中多个属性、操作或者行为的载体。例如:在“RabbitAdvisors”中,专栏、课程文章、订阅都是实体。但是在领域模型中实体与传统架构中的实体有类似的地方但是不完全一样, 在DDD实体的代码形态一般有四种形态:

失血模型模型仅仅包含数据的定义和getter/setter方法,业务逻辑和应用逻辑都放到服务层中。这种类在Java中叫POJO。

贫血模型:贫血模型中包含了一些业务逻辑,但不包含依赖持久层的业务逻辑。这部分依赖于持久层的业务逻辑将会放到服务层中。

充血模型:充血模型中包含了所有的业务逻辑,包括依赖于持久层的业务逻辑。

胀血模型:胀血模型就是把和业务逻辑不想关的其他应用逻辑(如授权、事务等)都放到领域模型中。

建议实体采用贫血模型,实体和领域服务共同构成领域模型。这样可以使得实体具备业务知识,但又不至于太过臃肿。

领域模型中的实体是多个属性、操作或行为的载体。

事件风暴中,我们可以根据命令、操作或者事件,找出产生这些行为的业务实体对象,进而按照一定的业务规则将依存度高和业务关联紧密的多个实体对象和值对象进行聚类,形成聚合。可以这么理解,实体和值对象是组成领域模型的基础单元。

1.3.2.2 实体的运行形态

DDD里,这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,跨多个实体的领域逻辑则在领域服务中实现。

充血模型和贫血模型,其实就是一个相对的概念,在我们之前的MVC架构设计中, 一般数据放在数据层,也就是实体中只包含属性,对应的行为放在服务层, 这种实体不包含任何行为只包含属性的模型称之为贫血模型,而充血模型就是实体中包含属性与行为

1.3.2.3 实体的运行时态

实体以DO(领域对象)的形式存在,每个实体对象都有唯一的ID。

DDD是先构建领域模型,针对实际业务场景构建实体对象和行为,再将实体对象映射到数据持久化对象

实体具有业务属性、业务行为和业务逻辑

1.3.3 值对象

定义:通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。在DDD中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。值对象没有唯一标识,没有生命周期,不可修改,当值对象发生改变时只能替换。

值对象的业务形态:大多数情况下实体具有很多属性,这些属性一般都是平铺,但有的属性进行归类和聚合后能够表达一个业务含义,就将这些属性封装到一起形成值对象,从而方便沟通而无需关注细节,因此可以说值对象就是用来描述实体的特征。当然实体的单一属性也是值对象。

值对象的代码形态:值对象有两种:单一属性的值对象,例如字符串、整型、枚举等;多个属性的值对象,这时候设计成class,包含多个属性,但是没有ID,值对象中可以嵌套值对象。

1.3.3.1 值对象运行时态

在DDD中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象值对象本质上就是一个集合集合内容包含若干个用于描述目的、具有整体概念和不可修改的属性。在领域建模的过程中,值对象可以保证属性归类的清晰和概念的完整性,避免属性零碎。一般来说[省、市、区]就可以看成一个值对象用来描述实体的地址

人员实体原本包括:姓名、年龄、性别以及人员所在的省、市、县和街道等属性。这样显示地址相关的属性就很零碎了对不对?现在,我们可以将“省、市、县和街道等属性”拿出来构成一个“地址属性集合”,这个集合就是值对象了

值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。

1.3.3.2 值对象的代码形态

值对象在代码中有这样两种形态。如果值对象是单一属性,则直接定义为实体类的属性;如果值对象是属性集合,则把它设计为 Class 类,Class 将具有整体概念的多个属性归集到属性集合,这样的值对象没有ID,会被实体整体引用。我们看一下下面这段代码,person 这个实体有若干个单一属性的值对象,比如Id、name等属性;同时它也包含多个属性的值对象,比如地址 address。

1.3.3.3 值对象的运行形态

值对象嵌入到实体的话,有这样两种不同的数据格式,也可以说是两种方式,分别是属性嵌入的方式和序列化大对象的方式。引用单一属性的值对象或只有一条记录的多属性值对象的实体,可以采用属性嵌入的方式嵌入。引用一条或多条记录的多属性值对象的实体,可以采用序列化大对象的方式嵌入

1.以属性嵌入的方式:

2.以序列化大对象方式:

 1.3.3.4 实体和值对象的关系

 实体和值对象是微服务底层的最基础的对象,一起实现实体最基本的核心领域逻辑。

 传统的数据模型设计通常是一个表对应一个实体,一个主表关联多个从表,当实体表太多的时候就很容易陷入无穷无尽的复杂的数据库设计,领域模型就很容易被数据模型绑架。

在领域模型中人员是实体,地址是值对象,地址值对象被人员实体引用。在数据模型设计时,地址值对象可以作为一个属性集整体嵌入人员实体中,组合形成上图这样的数据模型;也可以以序列化大对象的形式加入到人员的地址属性中,前面表格有展示。从这个例子中,我们可以看出,同样的对象在不同的场景下,可能会设计出不同的结果。有些场景中,地址会被某一实体引用,它只承担描述实体的作用,并且它的值只能整体替换,这时候你就可以将地址设计为值对象,比如收货地址。而在某些业务场景中,地址会被经常修改,地址是作为一个独立对象存在的,这时候它应该设计为实体,比如行政区划中的地址信息维护。

https://zhuanlan.zhihu.com/p/490244447?utm_id=0

 

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值