DDD建模咨询:采购与销售发票的聚合设计方案选型
关于DDD中采购/销售发票建模的方案分析
嘿,这个问题在DDD领域建模里算是个典型场景,我来分享下我的观点:
方案1:独立的PurchaseInvoice和SalesInvoice聚合
这种方案更贴合DDD的核心理念,原因如下:
- 符合单一职责与领域边界:采购发票和销售发票本质是两个不同的业务场景——一个对应采购入库的凭证,核心行为是触发库存增加;另一个对应销售出库的凭证,核心行为是触发库存减少。分开成独立聚合后,每个聚合只专注于自身领域的业务规则,边界清晰,不会出现逻辑混杂的情况。
- 扩展性更强:后续业务迭代中,两种发票大概率会衍生出各自独有的逻辑——比如PurchaseInvoice可能需要处理供应商对账、预付款抵扣、采购退货关联;SalesInvoice可能需要处理客户回款跟踪、返利计算、销售退货冲减。独立聚合可以在不影响彼此的前提下,各自扩展业务能力,避免出现“大而全”的臃肿模型。
- 业务规则内聚:每个聚合根可以将自身的核心行为(如
PurchaseInvoice.ApplyToInventory()、SalesInvoice.DeductFromInventory())封装得更纯粹,不用通过条件判断来区分业务逻辑,代码可读性和维护性都会更好。
方案2:单一Invoice聚合加鉴别器
这种方案仅适用于两种发票业务逻辑高度同质化、几乎没有差异化扩展需求的极端场景。但结合你提到的核心行为差异(加/减库存),强行合并会带来明显问题:
- 违反高内聚原则:把两种不同业务场景的逻辑塞进同一个聚合,会导致Invoice的职责模糊,后续新增差异化规则时,只能通过大量的
if/switch判断(比如判断InvoiceType是采购还是销售)来分支处理,代码会变得越来越臃肿,难以维护。 - 领域概念混淆:DDD强调模型要映射真实的业务领域,采购发票和销售发票在业务语境中是两个独立的概念,强行合并成一个模型,会弱化领域语言的表达能力,不利于团队统一业务认知。
结论
优先选择方案1,分别定义PurchaseInvoice和SalesInvoice两个独立聚合。这是DDD中“根据业务边界划分模型”“聚合根封装专属业务规则”的典型实践,能更好地支撑业务的长期迭代。
内容的提问来源于stack exchange,提问作者gDir
相关产品推荐
相关产品推荐

