当前位置: 首页 > news >正文

领域驱动设计(DDD)【21】之值对象的优势

文章目录

  • 一 内存布局分析
    • 1.1 对象的内存布局
    • 1.2 实体的内存布局
    • 1.3 值对象的内存布局
  • 二 数据库布局分析
    • 2.1 实体的数据库布局
    • 2.2 值对象的数据库布局
      • 2.2.1 两种方式
      • 2.2.2 两种方式的比较
      • 2.2.3 值对象的特点

  • 相较于实体,值对象的优点,主要体现在内存和数据库布局的灵活性上。有了这种灵活性,就可以根据性能、编程方便性等因素,决定值对象的不同实现方式。其次,值对象的不变性也会带来更高的程序质量。

一 内存布局分析

  • 内存布局就是程序在运行时,程序数据在内存的存储方式。

1.1 对象的内存布局

  • 假如有一个员工,名字叫“张三”,出生日期是“1990年1月1日”,员工号是“1001”。他有两个技能:一个是Go语言,做过3年,达到中等水平;另一个是Java语言,做过10年,达到高级水平。他还有两段工作经历:从“2017年1月1日”到“2022年1月1日”在“ABC Inc”公司工作;从“2014年1月1日”到“2016年12月31日”在“123 Inc”工作。
  • 员工对象图如下:
    在这里插入图片描述
  • 员工展开对象图
    在这里插入图片描述

1.2 实体的内存布局

  • 对于实体而言,关键原则:在同一个线程里,一个实体对象在内存空间里只能出现一次。也如果同一个实体在内存里被多个对象引用,那么这个实体必须被多个对象共享。如员工和组织的关系图:
    在这里插入图片描述
  • 或者这张情况
    在这里插入图片描述

1.3 值对象的内存布局

在这里插入图片描述

  • 假如员工张三和李四,都在2014年1月1日到2016年12月31日,在“123 Inc”公司工作。那么,当张三和李四同时装入内存的时候,内存布局可以有两种:一种是共享值对象,另一种不共享。
    在这里插入图片描述
    在这里插入图片描述
  • 两种值对象的内存分布都是正确的。
  • 要实现对象的共享,其实需要更复杂的编程,所以值对象在内存里多数是不共享的。比如 Java 语言里,默认情况下,字符串(String)、整数(Integer)等都是不共享的。但有时候,JVM 会“偷偷地”把相同的字符串共享,以便节省内存空间。不过,这对程序员是不可见的,我们总是应该假定字符串没有共享。
  • 当值对象的体积比较大,数量比较多,共享值对象可以节省大量内存的时候,就可以采用共享的方式。这种用法实际上是一种设计模式叫做“享元”,也就是共享的单元(Lightweight)。

二 数据库布局分析

2.1 实体的数据库布局

  • 在数据库表里,一个实体也只能有一条记录,不应该重复。以员工和组织关系为例。

第一种方式

  • 员工(emp)表的数据
idtenent_idorg_idnumnamegenderdob
11100001张三M1990-1-1
21100002李四F1995-1-1

  • 组织(org)表的数据:
idtenent_idname
11IT 部

第二种方式

  • 员工(emp)表的数据
idtenent_idorg_idnumnamegenderdob
11100001张三M1990-1-1
21200002李四F1995-1-1

  • 组织(org)表的数据:
idtenent_idname
11IT 部
21IT 部

2.2 值对象的数据库布局

  • 值对象在数据库的存储方式比较灵活。以员工和工作经验为例。

  • 员工(emp)表的数据
idtenent_idorg_idnumnamegenderdob
11100001张三M1990-1-1
21100002李四F1995-1-1

  • 组织(org)表的数据:
idtenent_idemp_idcompanystart_dateend_date
111123Inc2014-1-12016-12-31
212123Inc2014-1-12016-12-31

  • 在内存布局里面,时间段对象占有自己的内存空间,但在数据库里,并没有单独的“时间段表”。相反,时间段的属性,也就是开始日期和束日期,是工作经验表里的两个字段。也就是说,时间段这个值对象被“嵌入”到工作经验表里了。这种“嵌入”到所属实体表的方式,正是值对象最常见的存储方式。
  • 在数据库里是同一个表,在内存里却是不同的对象,这种数据库和内存的差异,称为阻抗不匹配。阻抗不匹配有多种形式,对象的嵌入式存储只是其中一种。在程序里进行数据存取的时候,就要进行转换,来消除这种不匹配。这种转换工作,是在仓库,也就是 Repository 中完成的。其实,消除这种阻抗不匹配,正是像 Hibernate 这样的 ORM 框架的主要目的之一。

2.2.1 两种方式


第一种

  • 假设李四和张三是合租的房子,两个人的地址一样。在概念上,两个人共享同一个地址。

  • 员工 (emp) 表的数据

idtenent_idorg_idnumnamegenderdob
11100001张三M1990-1-1
21100001李四F1995-1-1
  • 地址 (addr) 表的数据:
idtenent_idemp_idprovinecitydistrictstreetnum
111广东深圳南山区文明路123
212广东深圳南山区文明路123

  • 同一个地址信息存了两遍。这种情况对于实体是不对的,但对于值对象就没有问题,这同样是因为值对象的不变性。这种不变性在数据库操作的体现是:假如李四搬走,那么应该把和他相关的地址记录删除,再插入一条新地址,而不是改变地址表里原来的记录。

第二 种

  • 员工 (emp) 表的数据
idtenent_idorg_idnumnamegenderdobaddr_id
11100001张三M1990-1-11
21100001李四F1995-1-11
  • 地址 (addr) 表的数据:
idtenent_idprovinecitydistrictstreetnum
111广东深圳南山区文明路

  • 地址表里不再有员工的 ID(emp_id),反之,员工表里有一个地址 ID(add_id),指向地址表。

2.2.2 两种方式的比较

  • 共享值对象的好处包括两点:节省存储空间、容易通过数据库查询找到住在同一个地址的人。代价是删除员工的时候不能随便删地址。如果所有使用这个地址的人都被删除,就会留下垃圾数据。所以需要有清理垃圾数据的机制。由于现在硬盘都比较便宜,所以不共享的方式反而比较常用

2.2.3 值对象的特点

首先,值对象是不可变的,所以采用值对象就可以减少出错的几率。
其次,值对象具有不可变性,使用值对象,也可以减少并发错误。
最后,函数式编程总是假定被操作的对象是不变的,因此,使用值对象也更容易进行函数式编程。

http://www.lryc.cn/news/576665.html

相关文章:

  • WebRTC(十二):DTLS
  • PowerBI 柱状图显示MoM销量环比示例,以及解决相同列值时设置柱子颜色的问题
  • 【转】PostgreSql的镜像地址
  • 一个简单测试Deepseek吞吐量的脚本,国内环境可跑
  • QTreeWidget 简单使用
  • web自动化测试常见函数
  • 西门子S7-200 SMART PLC:小型自动化领域的高效之选
  • 华为云鸿蒙应用入门级开发者认证 实验部分题目及操作步骤
  • 基于Uniapp+SpringBoot+Vue 的在线商城小程序
  • AI 在金融领域的落地实践:从智能风控到量化交易的技术突破与案例解析
  • 【Docker基础】Docker容器管理:docker stats及其参数详解
  • 使用asyncio构建高性能网络爬虫
  • 华为云Flexus+DeepSeek征文|基于Dify构建AI资讯语音播报工作流
  • Python pyserial库【串口通信】全面讲解
  • 从傅立叶级数到傅里叶变换和离散傅里叶变换及其逆变换:FS FT DFT IDFT
  • 华为云Flexus+DeepSeek征文 | 华为云ModelArts Studio实战指南:创建高效的AingDesk知识库问答助手
  • Java锁机制知识点
  • Java安装与使用教程
  • FPGA设计的上板调试
  • zookeeper Curator(2):Curator的节点操作
  • 移动端日志平台EMAS
  • 在C++中#pragma“可选预处理指令的作用“。
  • OpenCV图像噪点消除五大滤波方法
  • springboot+Vue逍遥大药房管理系统
  • Redis—主从复制
  • 多径信道下移动通信信号均衡技术研究与实现
  • 常用工具库
  • 领域驱动设计(DDD)【22】之限定建模技术
  • electron中显示echarts
  • 顺序表应用实践:从通讯录实现到性能优化深度解析