DDD领域驱动设计之聚合

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lxy344x/article/details/81327683

       小编在 2016 年初次接触领域驱动设计,可能因为之前没有留意,感觉它还不怎么被大家认可,实践 1 年多的时间以来,伴随着业务对微服务的渴求,也越来越多的看到有关微服务的文章里在提倡采用 DDD 领域驱动设计来实现模型设计,架构设计。领域驱动设计包括战略建模(即架构设计)和战术建模(即模型设计)。战术模型中包含领域,子域,限界上下文,聚合,实体,值对象,领域服务,领域事件,模块,工厂,资源库等等。本 chat 的核心是分享领域驱动设计中战术模型设计的聚合,实体的设计,这也是采用 DDD 最为核心的内容,分为以下几个方面:

  1. 什么是聚合
  2. 如何创建聚合
  3. 聚合的设计原则

什么是聚合?

        首先谈什么是领域,小编第一次分享这个话题的时候,有人问到什么是领域?小编被问到了,让百科解决下吧,领域,一种专门活动或事业的范围、部类或部门。例如,一个电商系统,一个在线教育平台等都是一个领域,领域中存在问题空间和解决问题空间,问题空间由子域组成,解决问题空间则由多个限界上下文,即一组特定的软件模型。我们的战术模型设计也就产生在每个限界上下文的范围内。 聚合是一种特殊的实体,实体的概念是:一个唯一的东西,并且可以再相当长的一段时间内持续地变化; 聚合包装一组高度相关的对象,作为一个数据修改的单元。聚合最外层的对象称为聚合根,它是一个实体。 聚合根划分出一个清晰的边界,聚合根外部的对象,不能直接访问聚合根内部对象,如果需要访问内部对象,必须首先访问聚合根,再导航到聚合的内部对象。

如何创建聚合?

根据聚合的定义我们可以获取以下信息:

       聚合要有唯一标识;

       一段时间内持续变化;

       组装高度相关的对象;

        创建一个新聚合时,我们希望通过构造函数来初始化足够多的实体状态,哪些内容需要传给构造函数呢? 唯一标识,能够唯一的确定一个对象;对象的一个或多个不变条件,不变条件即使在整个实体生命周期中都必须保持事务一致性的状态。比如用户必须有名字,性别。或者说,如果实体的不变条件要求改实体所包含的对象都不能为 null 状态,或者由其他状态计算所得,那么这些状态需要作为参数传递给构造函数。 并通过修饰符(private,default,protect,public)来保证对象数据的一致性和不变性。 另外,创建聚合时,聚合内部通过验证的方式来保证数据的有效性。所以聚合中会提供一些验证方法,验证一般有属性验证,整体对象验证,组合对象验证等。

 聚合的设计原则:

             聚合内事务一致性

             设计尽可能的小聚合

             通过唯一标识引用其它聚合

             聚合外使用最终一致性

扫描二维码关注公众号,回复: 3838476 查看本文章

             优先使用值对象

             聚合中避免使用依赖注入

             迪米特法则

1、聚合内事务一致性

        即一个业务规则内,该规则应该总是保持一致的。事务一致性可分为立即性,原子性。聚合边界之内的所有内容组成了一套不变的业务规则,任何操作都不能违背这些规则。边界之外的任何东西与该聚合都是不相关的。因此,聚合表达了与事务一致性边界相同的意思。在一个事务中只能修改一个聚合实例,这是设计聚合的重要经验原则,也是业务为什么要使用聚合的原因。

2、设计尽可能的小聚合

       聚合的设计尽量小到不可再拆分,聚合的修改要保证在一个事务边界内,大聚合中很难保证,聚合的事务原子一致性也只能通过最终一致性来保证,大聚合在查询时需要加载的数据,涉及到的实体较多,会降低查询的性能。

3、通过唯一标识引用其他聚合

        引用聚合和被引用聚合不可以在同一个事务中进行修改。如果你试图在单个事务中修改多个聚合,这往往意味着此时的一致性边界是错误的。发生这样的情况通常是因为我们遗漏了某些建模点或者尚未发现通用语言中的某个概念。如订单中只会留有货品的 ID。

4、聚合外使用最终一致性

        经过一段时间后要求能访问到更新后的数据,则是最终一致性。任何跨聚合的业务规则都不能总是保持处于最新状态。通过事件处理、批处理或者其它的更新机制,我们可以在一定时间之内处理好依赖。这个原则的意思是说:聚合内事务一致性,聚合之间最终一致性。

5、优先使用值对象

         我们应该尽量的将聚合根所包含的其它聚合建模成值对象,而不是实体。在不至于对模型或基础设施造成明显影响的情况下,采用值对象全部替换的方式是最好的选择。(值对象,只作为数据传输对象,无状态变化,且一旦创建不再修改)

6、聚合中避免使用依赖注入

         在一个高吞吐量、高性能的领域中,内存吃紧,垃圾回收周期漫长,那么我们就不应该给系统增加不必要的负担。比如,我们可以在调用聚合命令方法之前查找到所依赖的对象。当然,以上只是告诫大家不要在聚合中注入资源库和领域服务(资源库,负责数据存储对接存储系统;领域服务,负责聚合间的业务逻辑处理)。

7、迪米特法则

       迪米特法则:强调了“最小知识”原则。 在客户端对象使用服务对象时,它应该尽量少的知道服务对象的内部结构。 客户端对象不应该知道任何关于服务对象属性的信息。 客户端对象可以根据表层接口调用服务对象的命令方法。

   

猜你喜欢

转载自blog.csdn.net/lxy344x/article/details/81327683