DDD领域驱动设计:聚合含实体集合合理性及实体对外可见性咨询
问题1:聚合包含实体集合的设计合理性
单实体聚合是DDD领域公认的优先推荐实践,小聚合可以降低并发冲突概率、提升数据加载性能,也更便于维护业务规则,但这并非强制要求,聚合包含多个实体属于完全合规的常规设计,判断合理性的核心标准只有两个:
- 是否符合强一致性边界要求:你举的Month聚合包含Day实体的场景,只要业务规则要求Day的变更必须和Month的状态保持强一致(比如单日消费扣减必须同步校验月度总预算、单日数据修改必须同步更新月度统计字段等),该设计就是合理的。如果Day可以独立被其他业务逻辑修改、不需要和Month做规则联动,应该把Day拆为独立聚合根,Month和Day仅用ID关联即可。
- 集合规模是否可控:你这个场景下Month下最多只有31个Day对象,集合大小完全可控,不存在加载、查询性能问题。如果实体集合会无限膨胀(比如订单聚合下挂载数十万条操作日志),则绝对不能采用该设计,必须拆分为独立聚合。
问题2:聚合内部实体的对外可见性规则
聚合的核心设计原则是所有对聚合内部状态的修改必须通过聚合根完成,你将聚合根设为包私有避免外部直接操作的设计是符合规范的,内部实体的可见性需要严格遵循以下规则:
- 禁止直接对外暴露内部实体的引用:内部实体的生命周期完全受控于聚合根,外部如果拿到实体引用直接修改,会绕开聚合根定义的业务校验规则,破坏数据一致性,哪怕仅用于查询场景也不能直接返回实体本身。
- 对外透出必须封装为不可变的值对象(VO):不管是响应外部查询请求,还是存入领域事件的Payload,都需要将实体的属性拷贝到不可变的VO中再对外透出,从根本上避免外部操作影响聚合内部状态。如果有修改内部实体的需求,必须由聚合根暴露对应的操作方法,外部传入目标实体的唯一标识和修改参数,由聚合根内部定位到实体、完成业务规则校验后再执行修改。
补充:如果领域事件需要携带Day的唯一标识做后续异步处理,直接在透出的VO中携带Day的业务ID即可,无需透出完整实体。
内容的提问来源于stack exchange,提问作者Drake
相关产品推荐
相关产品推荐

