首页
3D照片墙
统计
留言
Search
1
1.OAuth 的简单理解
115 阅读
2
多个拦截器的执行顺序
105 阅读
3
基于Annotation方式的声明式事务
102 阅读
4
6.设计模式汇总
101 阅读
5
Unity 依赖注入
98 阅读
Java
JDBC
Spring
Spring MVC
SpringBoot
SpringCloud
MybatisPlus
Mybatis
Maven
SpringSecurity
JVM
java注解与反射
Java JUC并发编程
SSM
.NET
IdentityServer4
EF
.Net Core
AbpVNext + DDD
.NET MVC Api
前端
Jquery&JavaScript
uniapp
VUE
Echars
Vue底层原理
Python
Django
软考笔记
软件设计师
1.计算机组成与体系结构
10.面向对象技术
11.UML类图建模
12.面向对象程序设计
13.数据结构
14.算法基础
16.知识产权标准化
17.程序设计语言
2.操作系统
3.数据库
4.数据库设计
5.计算机网络
6.信息安全
7.系统开发基础
8.项目管理
9.数据流图
架构设计
CQRS架构
DDD架构
数据库技术
SQL锁
SqlServer
Oracle 主从备份
Oracle RAC集群
Mysql
云原生/容器技术
kubernetes
Docker
数据结构与算法
常用中间件
Redis
RabbitMQ 消息队列
ElasticSearch
其他
PHP
OAuth 2.0
WebSocket
ArkTs Harmony 开发
运维
Search
标签搜索
排序算法
vue
算法
遍历
docker
线性
数组
dom
synchronized
数据库
xml语言
log4j
bigint
静态函数
静态方法
哈夫曼树
const
冒泡排序
商标设计
命令模式
Bi8bo
累计撰写
304
篇文章
累计收到
6
条评论
首页
栏目
Java
JDBC
Spring
Spring MVC
SpringBoot
SpringCloud
MybatisPlus
Mybatis
Maven
SpringSecurity
JVM
java注解与反射
Java JUC并发编程
SSM
.NET
IdentityServer4
EF
.Net Core
AbpVNext + DDD
.NET MVC Api
前端
Jquery&JavaScript
uniapp
VUE
Echars
Vue底层原理
Python
Django
软考笔记
软件设计师
1.计算机组成与体系结构
10.面向对象技术
11.UML类图建模
12.面向对象程序设计
13.数据结构
14.算法基础
16.知识产权标准化
17.程序设计语言
2.操作系统
3.数据库
4.数据库设计
5.计算机网络
6.信息安全
7.系统开发基础
8.项目管理
9.数据流图
架构设计
CQRS架构
DDD架构
数据库技术
SQL锁
SqlServer
Oracle 主从备份
Oracle RAC集群
Mysql
云原生/容器技术
kubernetes
Docker
数据结构与算法
常用中间件
Redis
RabbitMQ 消息队列
ElasticSearch
其他
PHP
OAuth 2.0
WebSocket
ArkTs Harmony 开发
运维
页面
3D照片墙
统计
留言
搜索到
1
篇与
的结果
2022-03-12
基本概念 - 领域设计:Entity与VO
什么是状态 什么是标识 什么是Entity 什么是VO(ValueObject) 在设计中如何识别Entity和VO 要理解Entity和VO,需要先理解两个概念:「状态」和「标识」!我们先来聊聊「状态」! 状态 大家肯定都在淘宝买过东西吧!在淘宝购买商品后,会有一个订单,记录了你购买的商品信息、价格、店铺信息、还有一个特别重要的信息,就是订单状态。通过这个订单状态,我们可以知道我们的购物流程现在进行到哪一步了。如果你犹豫了很久才下定决心购买了一件心仪已久的商品,你是不是很在意订单状态?时不时要刷新一下页面,看看订单状态是否显示已送达了? 开发过系统的都知道,一般订单状态都是使用一个字段来表示的,比如status,不同的状态就是给status赋不同的值。但是这个status就是「订单状态」吗?难道状态就是一个字段?! Order{ product location seller buyer status ... } 你有没有想过,当我们说「状态」的时候,我们实际上指的是什么? 我们在很多场景下会用到「状态」这个词,比如: 你今天「状态」不错哦 朋友又发朋友圈「状态」了 我在淘宝买的商品已经是发货「状态」了 REST 以「你今天状态不错」这句为例,如果状态就是一个字段!那么,「你今天状态不错」就是status=1?!「你今天状态不行」就是status=0?!很明显,这不合理! 如果「状态」不是简单的一个字段的话,那么「状态」到底是什么呢? 其实在架构风格:你真的懂REST吗?已经提过了!文中对REST的解释,有这么一句:一个由网页组成的网络(一个虚拟状态机),用户通过选择链接在应用中前进(状态迁移),导致下一个页面(应用的下一个状态的表述)被转移给用户,并且呈现给他们,以便他们来使用。 结合上面的几个场景,你有没有发现,「状态」实际上表示的是「目标对象在当前时刻所呈现出的内容」!在软件系统中通过一个字段来表示状态只是一种简化手段! 如无特殊说明,下面所提到的「状态」指的是「目标对象在当前时刻所呈现出的内容」,而不是指状态字段 你今天「状态」不错哦:你今天给人的感觉很好 朋友又发朋友圈「状态」了:朋友圈当前的内容 我在淘宝买的商品已经是发货「状态」了:你的购物流程目前所在的环节 REST 既然「状态」表示的是「当前时刻所呈现出的内容」!那么说明了「状态」是个快照/瞬态!也就是说,「目标对象」有多个「状态」,「当前状态」只是「目标对象」众多「状态」中的一个! 大家应该玩过定格动画吧?就像下面这样(下图截自《大侦探福尔摩斯2:诡影游戏》): 图中的小册子就是「目标对象」,册子的每一页就是「状态」,当前展示出来的那一页就是「当前状态」! 在理解了什么是「状态」以后,我们就可以来初步区分Entity和VO了: Entity在整个生命周期中,有多个「状态」,也就是说「状态」是可变的(至于变不变就看实际情况了) 而VO在整个生命周期中,只有一个「状态」,也就是说「状态」不变 现在,问题又来了,对于VO来说,因为「状态」是不可变的,我们就可以用其「状态」来表示VO!但是对于Entity来说,因为有多个「状态」,且「状态」是可变的,那我们如何来表示呢?以上面的Order为例,假设同一个买家在同一个卖家那里买了两个同样的商品,那两个订单里的信息都是一样的,但是它是两个不同的订单,我们如何区分这两个订单呢? 现在就轮到下一个主角登场了:「标识」! 标识 说到「标识」,我们最先想到的是编程语言中的「引用」或「指针」!比如下面的代码: Order orderA = new Order("productA",...); Order orderB = new Order("productA",...); orderA.productName = "productB"; 前面两行,orderA和orderB虽然订单信息(状态)都相同,但是这是两个不同的订单 第三行,即使改了orderA的产品名称(状态),依然还是相同的订单 这解决了「区分相同状态的不同Entity」的问题,但是没有解决Entity有多个状态的问题。因为「标识」指向的是目标对象的当前状态。而且,很多编程语言中有个很大的问题,就是不区分「标识」和「状态」!什么意思呢? 假设我们在看一部电影,当我们开始观看时,就是这部电影生命周期的开始,观看结束就是这部电影生命周期的结束,在这段时间里,电影的画面(状态)一帧帧的呈现在我们面前,我们可以通过播放、快进、后退、暂停改变电影的状态,每个状态都是相互独立的,类似这样: 随着时间的改变,我们能获取到电影的不同状态,每个状态是相互独立的。但是实际上我们的代码逻辑像下面这样: var movie1 = new Movie(); movie1.setCurrentFrame("第三帧"); var currentMovie = movie1 movie1.setCurrentFrame("第四帧"); currentMovie // 还是第三帧吗? 电影播放到第三帧,我们用一个变量currentMovie保存了电影的当前状态(第三帧),但是后面电影播放第四帧了,currentMovie也就变成了第四帧的状态了。 语言中的这种「标识」(我称为「隐式标识」)还有另外一个问题,就是无法跨系统。比如,在分布式系统中,需要保证两个系统中的对象是同一个对象,这种「隐式标识」是做不到的。 所以「隐式标识」并不能满足我们的需求。我们需要「显示标识」,「显示标识」在现实中很常见: 每个人都有身份证,即使有两个人名字相同、性别一样、身材相同、甚至整容了样貌都一样,但是身份证号码是不一样的,身份证号码就是每个人的「显示标识」 一个产品线上生产的产品可以说一模一样,但是都会有一个唯一的产品编号,这个产品编号就是产品的「显示标识」 在上面购物的列子中,就相当于给Order一个唯一标识,比如一个唯一的订单号: Order{ orderNo // 显示标识 product location seller buyer status ... } 给定订单号以后,无论订单的状态如何变化,只要订单号不变,那么它就是同一个订单。 所以,「标识」是另一个区分Entity和VO的关键点: Entity有标识 而VO没有标识 注意标识并不一定只是一个字段,可能是多个字段的组合,这需要根据不同的业务逻辑来确定。比如在一个学校系统里,可以通过学年+班级+学号来标识一个学生。 Entity和VO 理解了标识和状态,我们就可以来定义Entity和VO了: Entity是具有多个「状态」的对象,「状态」在其生命周期中可能会改变,通过「标识」来唯一确定这个对象 VO只有一个「状态」,且是在创建时就确定的,也就是说VO是不可变的 现在我们知道了什么是Entity,什么是VO,那么我们如何在系统中识别哪些对象是Entity,哪些对象又是VO呢? 如何识别Entity和VO 一个对象是表示成Entity还是VO,取决于系统的关注点。 我们还以淘宝购物为例,假设你在某家店铺买了个商品,质量很好。过了一段时间后,你想再买一个,但是你记不得是哪家店了,于是你从已完成的订单列表中点击商品想进去再次购买。但是你点进去后发现,商品下架了。 这是因为「商品」在「订单系统」中是个VO,而在「商品管理系统」中是Entity!其实很好理解: 在「商品管理系统」中,系统需要关注「商品」的「状态」,需要维护是否上架、库存多少、各种属性等信息(多种状态)。就是说在「商品管理系统」中,商品状态是可变的。所以它也有「标识」,即商品ID 而「订单系统」并不关心「商品」的「状态」变化,它只关注在创建订单时,这个「商品」的当前「状态」是什么,并且在订单创建完成后,这个「商品」的「状态」就不会再改变了 在「商品管理系统」中,商品可以这样表示: Product { id // 商品标识 name desc status ... } 而在「订单系统」中,订单是个Entity,商品是个VO,可以这么表示: Order{ orderNo // 订单标识 product:Product status ... } Product { id // 这里不是标识,只是状态 name desc status ... } 注意这里的id并不是标识,这里的id实际上退化成了状态的一部分,保留这个id是为了和「商品管理系统」进行交互,通过id从商品管理系统中查询商品。当然还有其它方式,例如保存「商品管理系统」中该商品的历史URL。 总结 本文从对「状态」和「标识」的理解开始,一步步来解释什么是Entity和VO,以及如何在系统中识别Entity和VO。后面将进一步讨论Entity与VO的关系,以及与其它组件的关系,例如DTO,Service,Resporitory,DAO等 参考资料 《领域驱动设计:软件核心复杂性应对之道》 《实现领域驱动设计》 《Clojure编程乐趣》 《七周七并发模型》
2022年03月12日
89 阅读
0 评论
31 点赞