领域驱动设计学习笔记
专用名词
Entity和Value Object
entity:指的是实体,用于生命周期和标识,相当于传统意义上的数据库中的一个实体;
value object(值对象):侧重于描述没有唯一标识符但有明确值的领域概念。「可以称value objec是entity的一个属性」
例子1:以电商微服务系统中的商品模块,订单模块为例。
# 商品
class Product{
String id;//主键
String skuId;//唯一识别号
String productName;
Bigdecimal price;
Category category;//分类
List<Specification> specifications;//规格
...
}
# 订单
class Order{
String id;//主键
String orderNo;//订单号
List<OrderItem> orderItems;//订单明细
BigDecimal orderAmount;//总金额
...
}
# 订单明细
class OrderItem{
String id;
String productId;//只记录一个id用于必要的时候发起command操作
String skuId;
String productName;
...
BigDecimal snapshotPrice;//下单时的价格
}
在这个例子当中,Order 和 Product都是entity,而OrderItem则是value object。对于标识来说,entity是作为数据本身存储于数据库,主键id是一个标识,value object是作为领域对象本身,而OrderItem中的productId,id不能称之为标识,因为整个OrderItem对象是依托于Order存在的,Order不存在,则OrderItem没有意义。
例子2: 汽车和轮胎的关系是entity和value object吗?
这个例子其实是一个陷阱题,因为他没有交代限界上下文(BC),场景不足以判断。对于用户领域而言,的确可以成立,汽车报废之后,很少有人会关心轮胎。轮胎和发动机,雨刮器,座椅地位一样,只是构成汽车的一些部件,和用户最紧密相关的,只有汽车这个entity,轮胎只是描述这个汽车的属性(value object);场景切换到汽修厂,无论是汽车,还是轮胎,都是汽修厂密切关心的,每个轮胎都有自己的编号,一辆车报废了,可以安置到其他车上,这里,他们都是entity。
由于value object是依赖于其所指向的entity标识所存在的,如果失去对应的标识entity后,value object将变得没有意义,因此应尽量完全清除VALUE OBJECT之间的双向关联。
问题考虑
- 由于value object是依赖于其所指向的entity标识所存在的,如果失去对应的标识entity后,value object将变得没有意义,因此应尽量完全清除VALUE OBJECT之间的双向关联。
- ENTITY和VALUE OBJECT往往由于粒度过细而无法提供对领域层功能的便捷访问。
- 鉴于粒度问题,可以考虑使用SERVICE来控制领域层中的接口的粒度,并且避免客户端与ENTITY和VALUE OBJECT耦合。
限界上下文(Bounded Context,BC)
模式Repository 聚合Aggregate 和聚合根Root
在微服务中我们常说划分服务模块,在领域驱动设计中,我们常说划分限界上下文。在微服务中,限界上下文将成为服务的边界,每个服务都代表一个限界上下文,只需关注该领域的业务需求和职责。服务之间通过API和异步消息进行通信,通过限界上下文可以很好地管理和维护服务之间的依赖关系。
在面向对象的世界里,用抽象来封装模型中的引用,聚合就是指一组相关对象的集合,我们把它作为数据修改的单元。每个聚合都有一个聚合根(root)和一个边界(boundary)。边界定义了聚合内部有什么,而根则是一个特定的entity,两个聚合之间,只允许维护根引用,只能通过根引用去向深入引用其他引用变量。
案例1:电商系统中的订单和商品模块。在聚合模式中,订单不能够直接关联到商品的规格信息,如果一定要查询,则应该通过订单关联到的商品,由商品去访问商品规格。在这个例子中,订单和商品分别是两个边界,而订单模块中的订单entity和商品模块中的商品entity就是分别是各自模块的root。遵循这个原则,可以使我们模块关系不那么的盘根错节,这也是众多领域驱动文章中不断强调的划分限界上下文是第一要义。
技术方案始终有代替方案,决定微服务的不是框架的选择,不仅仅是restful或者rpc的接口设计风格的抉择,而更应该关注拆解,领域,限界上下文,聚合根等等一系列事物,这大概就是领域驱动设计对微服务架构的指导意义。
参考文献:[1]名词解释博客
[2]《领域驱动设计 软件核心复杂性应对之道 修订版》