从简单到复杂依次为:

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" ;

// 即将生成 Productldproductld = 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或多个匹配对象。接着用户要在结果中选择某特定对象。所选对象的身份标识将作为本地标识。外部实体的一些额外属性也可能被复制到本地实体。

缺陷

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

参考 - 《实现领域驱动设计》

ddd 访问权限_DDD领域驱动设计实战 - 创建实体身份标识的常用策略相关推荐

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

    从简单到复杂依次为: 3.1.1 用户提供唯一标识 这时用户将输入一些可识别的数值或符号,或从已有标识中选其一,然后创建实体对象.这是一种非常简单方案,但也可能变得复杂. 由于需用户自己生成高质量的标 ...

  2. DDD领域驱动设计实战 - 创建实体身份标识的常用策略

    从简单到复杂依次为: 3.1.1 用户提供唯一标识 这时用户将输入一些可识别的数值或符号,或从已有标识中选其一,然后创建实体对象.这是一种非常简单方案,但也可能变得复杂. 由于需用户自己生成高质量的标 ...

  3. ddd 访问权限_DDD 领域驱动设计-如何 DDD?

    注:科比今天要退役了,我是 60 亿分之一,满腹怀念-

  4. [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现...

    原文:[.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现 一.引言 在上一专题中,商家发货和用户确认收货功能引入了消息队列来实现的,引入消息队列的好处可以保证 ...

  5. [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店...

    原文:[.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店 一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Bytear ...

  6. 架构之路_DDD领域驱动设计总结

    推荐书籍:领域驱动设计 - 软件核心复杂性应对之道 - Eric Evans. 视频教程:DDD 微服务落地实战视频教程 一.DDD基础名词概念 领域驱动设计(DDD),它是针对复杂系统设计的一套整软 ...

  7. DDD(Domain Driven Design) 领域驱动设计从理论到实践 四

    - 接上 SOA 架构 ​     面向服务架构(Service Oriented Architecture,SOA)对于不同的人来说意思不同.这里梳理一下SOA原则: 服务契约 : 通过契约文档,服 ...

  8. DDD领域驱动设计实战-分层架构及代码目录结构

    代码结构 DDD并没有给出标准的代码模型,不同的人可能会有不同理解. 按DDD分层架构的分层职责定义,在代码模型里分别为用户接口层.应用层.领域层和基础层,建立了 interfaces.applica ...

  9. 领域驱动设计 软件核心复杂性应对之道_DDD - 领域驱动设计对软件复杂度的应对(上)...

    不管是因为规模与结构制造的理解力障碍,还是因为变化带来的预测能力问题,最终的决定因素还是因为需求.Eric Evans 认为"很多应用程序最主要的复杂性并不在技术上,而是来自领域本身.用户的 ...

最新文章

  1. CMD 输入中文看不到输入法的解决方法
  2. Spring Boot骚操作-多数据源Service层封装
  3. python使用imbalanced-learn的BorderlineSMOTE方法进行上采样处理数据不平衡问题
  4. Android React Native 笔记(二):Component生命周期
  5. gridstack 宽度改变_Model Y在Model 3有哪些改变?
  6. assignment symbolic automaton verilog设计
  7. JSP JavaBean
  8. php div行内块元素,行内元素与块级元素的区别详细介绍
  9. android studio防止反编译,防反编译利器-Android studio混淆代码压缩apk包体积
  10. Java工程师必学知识点【吊打面试官系列】
  11. 西门子STEP7 MICROWIN V4 SP5 下载
  12. C#中手动引用COM组建的例子
  13. Windows虚拟设备驱动开发总结
  14. 1024程序员节节日快乐
  15. 聚合支付、第四方支付有哪些平台?
  16. Struts2(一)
  17. 拔开云雾的linux网络
  18. js后代选择器_后代选择器和子元素选择器的区别
  19. C++各行小数点对齐
  20. dcc-garch matlab,如何用Eviews或者MATLAB实现DCC-garch模型?

热门文章

  1. Unity3D Shader系列之透视效果XRay
  2. Tensorflow报错:ValueError: Trying to share variable ..., but specified shape ... and found shape ...
  3. MATLAB绘制圆柱体
  4. 【HTML】location对象
  5. 500internal privoxy error的一个解决思路
  6. 数据可视化之桑基图制作,其实很简单,只需拖拽就能搞定
  7. 计算机文档排版的心得体会,排版心得体会.docx
  8. Java之jstack工具的使用
  9. 轻松将多个圆通快递物流中含有多次揽收的单号归类
  10. Hackthebox-Craft (Machine Maker: rotarydrone)