DDD的一些基本概念

2021-06-10 15:38:22 浏览数 (1)

一、Entiry(实体)和Value Object(值对象)

1、实体

实体的定义在原书《领域驱动设计》中的描述如下:

一些对象主要不是由它们的属性定义的。它们实际上表示了一条“标识线”,这条线跨越时间,而且常常经历多种不同的表示。 领域驱动设计

听起来比较晦涩,可以概括几点:

1)、在同一类模型实中需要区别开来,一个实体是唯一的东西;

2)、每个实体有唯一标识来区别彼此;

3)、实体有生命周期,我们可以对它多次修改,但它仍然还是同一个实体。

2、值对象

当我们只关心一个模型元素的属性时,或者说对于同一类模型实例我们不用区别每一个时,只关心其属性时,这些对象就可以归为值对象。

相对于实体,值对象有几个特征:

1)不可变

即值对象是不能修改的,如果要修改则应该产生一个新对象,这样就不用管理其整个生命周期。

同样对于一个修改方法,以下是实体的伪代码:

代码语言:javascript复制
Public Class Order{
    pulic void setStatus(Status status){
      this.status = status;
    }
}

如果是值对象,则伪代码应该是这样的:

代码语言:javascript复制
Public Class Order{
    pulic Order setStatus(Status status){
      Order order = new Order(status);
      return order;
    }
}

2)、它没有标识,两个值对象是否相等只要比较属性即可。

说了这么多,我们可以举一些例子:

订单

这个模型在电商系统中比较常见,假如我昨天创建了一个订单,今天也创建了一个订单,在系统中这两个订单是不同的,两个订单通过订单号来区别彼此,并且订单需要管理其整个生命周期,包括从创建到支付再到发货,因此订单是实体。

发货地址

如果我要将一个订单发到深圳XX村XX街道,则我不用关心这个地址何时创建,我只需这个地址就行了,因此这个地址可以在昨天的订单使用,也可以在今天的订单使用,也没必要创建相同的2个地址。因为判断2个地址是否相同,是通过对比省、市、村、街道等属性,而不像上面的订单中,通过订单号来区别,因此地址是值对象。

上面这些举例是基于电商的场景来说的,如果一些场景发生变化,实际的模型可能有变化,比如说对于快递公司来说同一个目的地地址可能是一个宿舍,则这个地址需要表示为实体了,因为同一个地址可能对应多个目的地。

二、聚合

聚合是一组相关对象的集合,称之为修改单元。

每个聚合都有一个根和一个边界,根一般是一个实体,外部对象只能引用根,内部对象之间则可以相互引用。

为什么需要聚合呢,原书给的原因如下:

1)、保证对象更改后的一致性;

2)、保持固定规则;

这里还是以上面的订单为例,在电商系统中,一个完整的订单除了订单模型,还有地址、支付、物流等模型。

假如我们要修改发货地址,如果我们不通过订单去修改发货地址,则一些规则无法保证,如防止订单已经打包发货了的情况下是不允许修改发货地址的,如果先不从订单得到地址,而是从数据库中取出来直接修改地址,则这个规则可能被破坏了。

另外就有就是一个订单还在,但是地址已经删除了也是灾难,因此所有对地址的修改都应该从订单出去,先找到订单,然后通过订单去修改地址。

三、领域、子域、核心子域、支撑子域

领域是一个组织所做的事情以及其中包含的一切。

子域是领域一其中一个部分或者说某一个方面。

领域的概念太宽泛了,可以表示整个业务系统,而子域则是表示其中的一部分,之所以要这么分,因为分解是我们面对复杂系统的一个常用办法,只要将系统拆分的足够我们可以理解的范围才容易掌握,这里不用太纠结概念。

像公司做电商的,则电商就是你的领域,里面可以分解为商品子域、订单子域、物流子域等。

核心子域

领域中最核心的子域,即是有价值,最核心的业务子域。

支撑子域

领域中比较通用的子域,起支撑的子域。

如电商系统中订单应该是最核心的子域,短信、邮件发送可以作为通知子域,后者主要起支撑使用,也是比较通用的,在其它系统中也是可以用的。

之所以要区分两者 ,原书作者认为应该将主要精力放在核心子域,将技术最好的人投入到这些领域上,而支撑子域则用能力一般的人就可以,分清主、次。

实际上大部分公司是反过来的,认为通用子域对人的要求更高,这会导致最核心的业务域没有设计好。

0 人点赞