深入理解领域驱动设计中的聚合
点击上方“服务端思维”,选择“设为星标”
回复”669“获取独家整理的精选资料集
回复”加群“加入全国服务端高端社群「后端圈」
将实体和值对象划分为聚合并围绕着聚合定义边界。选择一个实体作为每个聚合的根,并仅允许外部对象持有对聚合根的引用。作为一个整体来定义聚合的属性和不变量,并把其执行责任赋予聚合根或指定的框架机制。
“架构并不由系统的功能决定,而是由系统的非功能属性决定”。
企业的员工可以通过该系统提交一个采购请求,一个请求包含了若干数量、若干类型的办公用品(称为采购项)。(1)
主管负责对采购申请进行审批。(2)
审批通过后,系统会根据提供商不同,生成若干订单。(3)
如果采购请求被删除,则相应的和该采购请求相关的采购项以及它们之间的关联都需要被删除——在数据库设计中,这种约束可以通过数据库外键来保证。
如果多个用户在对具有相关关系的数据进行并发处理,则可能涉及到复杂的锁定机制。例如,如果审批者正在对采购请求进行审批,而采购提交者正在对采购项进行修改,则就有可能导致审核的数据是过期数据,或者导致采购项更新的失败。
如果同时更新某些相关联的数据,也可能面临部分更新成功导致的问题——在数据库设计中,这类约束则需要通过 transaction 来保证。
...
getPurchaseRequest(requestId); =
purchaseRequest.getItem(itemId); =
item.setQuantity(1000);
savePurchaseItem(item);
生命周期一致性
问题域一致性
场景频率一致性
聚合内的元素尽可能少
public class PurchaseRequest {
private Set<PurchaseItem> items;
private User submitter;
...
}
r = purchaseRequestRepository.findOne(id);
//...一些修改
purchaseRequestRepository.save(r);
User user = userRepo.findOne(r.getSubmitter().getId());
//...一些修改
userRepo.save(user);
Submitter/Approver 对应的 User 对象脱离了 PurchaseRequest,仍然有单独存在的理由。
Product 对象脱离了 PurchaseRequest,是可以单独存在的。
public class PurchaseRequest {
private Set<PurchaseItem> items;
private UserId submitterId;
...
}
public class PurchaseItem extends ValueObject{
private ProductId product;
private Integer quantity;
...
}
public class PurchaseRequest {
private Set<PurchaseItem> items;
private User submitter;
...
}
聚合是面向对象的世界中建模的一个层次。它隐藏了细粒度对象,约束了对象之间的耦合。
聚合是一致性的边界,是对具有紧密关联关系的对象的封装。聚合封装了实体对象和值对象,并且采用其中最重要的一个实体对象作为聚合根。聚合根作为聚合的唯一外部入口,保证了业务规则和数据的一致性。
生命周期一致性
问题域一致性
场景频率一致性
聚合内的元素尽可能少
— 本文结束 —
关注我,回复 「加群」 加入各种主题讨论群。
对「服务端思维」有期待,请在文末点个在看
喜欢这篇文章,欢迎转发、分享朋友圈