c#获取对象的唯一标识_DDD领域驱动设计实战 - 创建实体身份标识的常用策略

从简单到复杂依次为:

3.1.1 用户提供唯一标识

这时用户将输入一些可识别的数值或符号,或从已有标识中选其一,然后创建实体对象。这是一种非常简单方案,但也可能变得复杂。
由于需用户自己生成高质量的标识。所以标识可能唯一,却有可能是不正确的。

缺陷

多数情况下标识不可变,用户无法修改标识。但有时赋予用户修改标识值的权限有好处。

例如,若将Forum和Discussion的名字作为唯一标识,那么发生拼写错误时怎么办,或用户之后想采用新名字怎么办?

  • Forum名字拼写错误,Discussion名字长度小于所要求的

要改变这些标识值需要多大代价?虽然用户提供的身份标识看似一种节约成本的做法,但也有可能不是。此时我们还可以依赖用户来提供唯一的、正确、稳定的对象标识吗?

为避免上述问题,需重新设计。开发需采用无故障的方法来保证用户输入的确是唯一的身份标识。虽然基于工作流的标识审批过程,对于高吞吐量的领域并无多大帮助,但是它对于生成具有可读性的身份标识来说却是必需的。如果这种方式生成的标识会在将来继续使用,而工作流也是可能的,那么添加一个额外的阶段来保证身份标识的质量是值得的。

通常将一些用户输入作为实体属性,这些属性可用于对象匹配,但并不将这样属性作为唯一身份标识。
简单属性可作为实体状态的一部分, 他们更容易修改,在这种情况下,我们需要考虑另外的方法来生成实体的唯一标识。

3.1.2 应用程序生成唯一标识

很多可靠方法可自动生成唯一标识,但若应用程序处于集群环境或分布在不同计算节点,就要注意了!
有些方法可以生成完全唯一的标识,比如UUID或者GUID。
以下是生成唯一标识的另一种方法,其中每一步生成的结果都将添加到最终的文本标识中:

  1. 计算节点的当前时间,以毫秒记
  2. 计算节点的IP地址
  3. 虚拟机(Java)中工厂对象实例的对象标识
  4. 虚拟机(Java)中由同一个随机数生成器生成的随机数

以上可产生一个128位唯一值,可通过一个32字节或36字节的16进制数的字符串表示。在使用36字节时,可用连字符-来连接以上各步骤生成结果,比如f36ab21c- 67dc-5274-c642-lde2f4d5e72ao在不用连字符时,即为32字节。但这都是一个很大的唯一标识,且不具可读性。
在Java里,以上方法被标准的UUID生成器所替代(自从Java 1.5),对应java.util.UUlD类。该类支持4种不同的唯一标识生成算法,这些算法都基于Leach-Saiz变量。使用JavaSE API,可简单生成伪随机的唯一标识: String rawld = java.util.UUID.randomUUID().toString();
以上代码使用了第4类算法,该算法采用高度加密的伪随机数生成器,而该生 成器又基于java.security.SecureRandom生成器。第3类算法采用对名字加密的方 法,它使用了java.security.MessageDigest类。我们可以通过以下方式生成一个基于名字的UUID:

String rawld = java.util.UUID.nameUUIDFromBytes( "Some text'*.getBytes()).toString ();

还可加密所生成的伪随机数

SecureRandom randomGenerator = new SecureRandom();int randomNumber = randomGenerator.nextInt();String randomDigits = new Integer(randomNumber).toString();MessageDigest encryptor = MessageDigest.getlnstance(nSHA-l"); byte[] rawIdBytes = encryptor.digest(randomDigits.getBytes());

接下来将 rawIdBytes 数组转换成16进制数的字符串表示即可。可先将随机数转换成字符串类型,再将该字符串传给UUID的nameUUlDFromBytes。工厂方法。

UUID是一种快速生成唯一标识的方法,它不需要与外界交互,比如持久化机制。即便需要在1秒钟之内多次创建实体,UUID生成器也可应付。对有性 能要求的领域来说,可缓存UUID实例,使其在背后不间断地向缓存中填入新UUID值。如果缓存中的UUID实例由于服务器重启而丢失,在不同唯一标识间不会存在缺口,因为所有标识都是随机,因此重新向缓存中填UUID值并不会对系统造成影响。

对于如此大的唯一标识,从内存使用角度看可能不实际。可采用由持久化机制生成的8字节长标识或甚至4字节长标识就够了。

通常并不会在用户界面上显示UUID: f36ab21c-67dc-5274-c642-lde2f4d5e72a,若UUID可隐藏或可使用可读性的引用技术,那便可使用完整UUID。
比如,可通过E-mail或其他消息机制发送具有URI的超媒体资源。此时,超媒体链接中的文本部分便可以用于隐藏UUID,就像 HTML中text里的text。
根据UUID能够表达实体的唯一程度,可只使用UUID的一部分标记实体。在聚合(10)边界内,可将缩短后的标识作为实体的本地标识。

本地标识表示在同一聚合中,一个实体的标识只需和该聚合中的其他实体区分即可。
Aggregate(聚合)是一组相关对象的集合,作为一个整体被外界访问,聚合根(Aggregate Root)是这个聚合的根节点。聚合根(Aggregate Root)的实体则需要全局的唯一标识

对于自己创建的标识生成器,依然可用UUID的某部分。 比如对于APM-P-08-14-2012-F36AB21C,该25字节的标识表示在敏捷项目管理上下文(APM)中创建的一个Product,创建时间为2012年8月14日。额外的F36AB21C唯一标识
即为UUID的第一部分,该部分用于区分同一天所创建的不同Product。
这样的标识

  • 满足可读性要求
  • 又提供很好的全局唯一性

用户并非唯一受益者,当这样的标识从一个限界上下文传到另一个时,开发者可立即识别实体源头。对于SaaSOvation来说,还可以向标识中加入租户信息。将这样的标识作为String来维护并不是一个好办法,此时使用一个值对象更加合适:

String rawId = "APM-P-0 8-14-2012-F36AB21C" ;// 即将生成 Productld productld = new Productld(rawld);Date productCreationDate = productld.creationDate();

客户可询问标识的细节信息,比如一个Product的创建时间,就已包含于标识。客户无需知道原始的标识格式,此时聚合根Product可通过creationDate方法向外界暴露该Produc啲创建时间,而客户并不 需要知道对创建时间的获取细节。

public class Product extends Entity {private ProductId productld;...public Date creationDate() {return this.productld().creationDate();}...}

也可通过第三方类库框架来生产实体的唯一标识。比如Apache Commons的Commons Id组件,该组件提供了5种标识生成器。
有些持久化存储,比如Redis也可生成唯一标识。

对于程序生成的标识来说,什么样的对象可以作为创建标识的工厂对象呢? 对于聚合根的唯一标识,我们可以采用资源库来生成唯一标识:

public class HibernateProductRepository implements ProductRepository (public Productld nextidentity() {return new Productld(java.util.UUID.randomUUID().toString().toUpperCase());}}

将唯一标识的生成放在资源库中是一种自然的选择。

持久化机制生成唯一标识

若从DB获取一个序列值(Sequence)或递增值,结果总是唯一。根据标识所需范围,数据库可生成2字节、4字节和8字节的唯一标识。在Java中的这些大小整数分别可表示

  • 32,767
  • 2,147,483,647
  • 9,223,372,036,854,775,807

种不同标识值。

缺陷

性能。
从DB获取标识比APP生成慢得多。一种解决方法是将数据库序列缓存在APP,比如缓存在资源库。
这固然是一种好方法,但若服务器节点需重启,那么将失去很大一部分标识值区间。若丢失区间无法接受或只需相对较小标识值(2字节整数),这缓存机制便不实用,也没必要。当然可以找回丢掉的标识值区间,但可能引入新麻烦。
如果可使用延迟生成,那缓存标识便不是问题。以下是如何使用Hibernate和Oracle的序列来生成标识:

product_seq

在采用MySQL的自增列时配置如下

这种方式的性能是很好的,同时配置Hibernate映射也是简单的。

3.1.3 另一个限界上下文提供唯一标识

若另一个限界上下文用于给实体标识赋值,那需要对每个标识进行查找、匹配和赋值。

最重要的是精确匹配。此时用户需提供一或多种属性,比如账户、用户名和E-mail地址,以精确定位需要匹配的结果。
通常匹配的输入是模糊的,导致多个查询结果,此时用户需要手动选择,如图

  • 从外部系统中获取需要查找的唯一标识。用户界面中可显示唯一标识(本图),也可不显示

用户输入了模糊查找信息,通过调用外部限界上下文的API,返回的结果可能是0、1或多个匹配对象。接着用户要在结果中选择某特定对象。所选对象的身份标识将作为本地标识。外部实体的一些额外属性也可能被复制到本地实体。

缺陷

对象同步可能是个问题。外部对象的改变将如何影响本地对象?如何知道所关联的对象已经改变了呢?
可通过事件驱动架构领域事件解决。本地限界上下文订阅外部系统中的领域事件,当本地上下文接收到外部系统的事件通知时,它将相应更新本地对象。有时同步事件可能由本地上下文发出,外部系统在接受到该事件时同样会做相应的更新操作。
要达到这样的目的并不容易,但这样做能够创建出更加具有自治性的系统。可将对象查找限定在本地对象中。这并不是说将外部对 象缓存在本地系统中,而是将外部概念翻译成本地限界上下文中的概念。
这是最为复杂的标识创建策略。要维护本地实体,我们不但需要考虑由本地 领域行为所导致的改变,还需要将外部系统也考虑在内。所以在使用这种策略时,应持保守态度。

参考

  • 《实现领域驱动设计》
0b5e4ae7a3f81e99ed45ac7cbacc3c9d.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/565639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java - 计算距离和反弹

根据提示输入次数,控制台输出对应的距离和反弹的距离。 效果演示 代码展示 package com.one;import java.util.*; public class High {public static Scanner input new Scanner(System.in);public static void main(String[] args) {System.out.println("…

【youcans 的 OpenCV 例程200篇】139. 灰度顶帽变换校正阴影

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】139. 灰度顶帽变换校正阴影 灰度级形态学将形态学操作从二值图像扩展到灰度图像。灰度形态学处理也…

quartus管脚分配后需要保存吗_电脑磁盘显示未分配怎么办?磁盘数据如何恢复?...

磁盘未分配的这部分磁盘空间上没有任何分区,也就是说这部分空间无法用来保存数据。那么,什么原因会导致磁盘变成未分配呢?1、删除分区:在平时使用电脑的时候会有意或无意的将分区删除掉。磁盘上的分区被删除之后,在磁盘…

【youcans 的 OpenCV 例程200篇】140. 灰度底帽变换校正光照

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】140. 灰度底帽变换校正光照 灰度级形态学将形态学操作从二值图像扩展到灰度图像。灰度形态学处理也…

java - 条件嵌套

根据提示输入一个分数,程序会计算并输出你输入成绩所在的等级,利用条件运算符的嵌套来完成此分类表示:学习成绩> 90 分的同学用 A 表示,60-89 分之间的用 B 表示,60 分以下的用 C 表示。 结果演示 代码演示 pack…

量化信噪比 非均匀量化_达尔优EM910牧马人轻量化游戏鼠标拆解评测

达尔优牧马人还真是一款经久不衰的模具,2012年推出至今,历经数次升级换代,已从最早期的“杀马特”风格变得硬核起来。为这一款中端定位的游戏鼠标,加入KBS按键衡力系统,也搭载有定制PMW3336光学传感器。然后机身配色设…

【youcans 的 OpenCV 例程200篇】141. 灰度底帽变换的三维地形图

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】141. 灰度底帽变换的三维地形图 5.3 灰度顶帽变换和灰度底帽运算 图像相减结合开运算和闭运算&am…

java - 水仙花数

经典的java程序练习,求水仙花数。 输出101-1000之间的所有水仙花数 水仙花数是指一个数各位上的数字的立方和等于该数本身 结果演示 代码演示 package com.two;public class Shuixianhua {public static void main(String[] args) {int num1, num2, num3;for(in…

【youcans 的 OpenCV 例程200篇】142. 基于灰度形态学的图像平滑

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】142. 基于灰度形态学的图像平滑 5.4 灰度形态学之图像平滑 由于开运算和闭运算对亮细节和暗细节的…

序列二次规划_最优控制与规划

(以下内容均来源于 CS 294 Lecture 8)首先我们假设环境是确定性的,即在某个状态执行某个动作之后,转移到的下一个状态是确定的,不存在任何随机性。而在这种情况下,我们想做的是在环境给了我们一个初始状态的…

java - 求a+aa+aaa+aa...a之和

求如 saaaaaaaaaaaa…a 之和,其中 a 是一个数字,根据提示输入个位数字和最高位数,计算并输出结果。 222222222222222(此时共有 5 个数相加),几个数相加由键盘控制 结果演示 代码演示 package com.two;import java.util.*;publ…

Go_defer详解

defer 1. 前言 defer语句用于延迟函数的调用,每次defer都会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行。 为了方便描述,我们把创建defer的函数称为主函数,defer语句后面的函数称为延迟函数。 延迟函数可能有输入…

【youcans 的 OpenCV 例程200篇】143. 基于灰度形态学的粒度测定

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】143. 基于灰度形态学的粒度测定 5.5 灰度形态学之粒度分析 粒度测度是指确定图像中颗粒的大小分布…

无法自动进入并单步执行服务器_膳食纤维无法进入血液执行营养功能,吃它有啥用?...

膳食纤维是植物性食物中所含不能被人体吸收、消化分解利用的碳水化合物,包含纤维素、半纤维素、木质秦和果胶等物质。其中,膳食纤维根据其水溶性又可再分为可溶性和不可水溶性。可溶性膳食纤维包括果胶、藻胶、树胶和黏液,多存在于水果、海藻…

java - 求素数

求素数,求出设定范围内所有的素数并进行控制台输出,输出101-200之间的所有素数 素数曾称质数。一个大于1的正整数,如果除了1和它本身以外,不能被其他正整数整除,就叫素数 结果演示 代码演示 package com.two; //输…

【youcans 的 OpenCV 例程200篇】144. 基于灰度形态学的纹理分割

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】144. 基于灰度形态学的纹理分割 5.6 灰度形态学之纹理分割 形态学的纹理分割是以纹理内容为基础&…

activity 变成后台进程后被杀死_Android 后台运行白名单,优雅实现保活

作者:NanBox链接:https://www.jianshu.com/p/32b7241124a2欢迎关注专栏:里面定期分享Android架构技术知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿。Android开发…

java - 菲波拉契数列 兔子个数

菲波拉契数列:有一对兔子,从出生后第 3 个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 结果演示 代码演示 package com.two;public clas…

【youcans 的 OpenCV 例程200篇】145. 形态学之边缘和角点检测

欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 【youcans 的 OpenCV 例程200篇】145. 形态学之边缘和角点检测 5.7 形态学之边缘和角点检测 边缘和角点不仅保留了图像的重要特征&…

tengine简单安装_树莓派使用宝塔面板安装LNMP环境

书接上回,前面说到我被垃圾Rock 64搞的死去活来,索性在树莓派上装了Ubuntu 20.04 LTS。 为了方便配置V2Ray,我忙活了一天终于把LNMP环境搞定了。下面说说怎么搞的,避免后面再踩坑。安装宝塔面板在安装之前需要先安装必要的软件。U…