我正在尝试在我的最新项目中应用 DDD。虽然我在确定将某些业务逻辑/计算放在哪里时遇到问题。
首先,我将描述业务流程,然后我将如何考虑实现它。
业务流程: 它只是将收据项目添加到收据中。但是,元素的价格取决于客户的类型和元素的数量。
即:“A”类型的客户想要购买 2 餐。在他的设置中,他被允许吃 1 顿折扣午餐,但因为他很饿,他吃了 2 顿。第一顿应该是 4 欧元(折扣价),第二顿应该是 6 欧元(全价)。
我的想法是:
Product - 一个实体(具有不同的限界上下文,将仅用作输入参数) - 字段:代码、名称、...、价格集合每个针对不同的客户类型。
ReceiptItem - 实体字段:产品代码、产品名称、数量、价格…… Receipt 作为聚合根 - 字段: 客户(实体)- 包含 ReceiptItems 的集合
在收据上,会有一个方法addItem(Product product, int count)
,我打算在这个方法中添加正确的价格计算。
回到我们的示例:receipt.addItem('menu1', 2)
所以我会检查客户类型以及允许他打折的午餐数量。鉴于上面的例子,我会看到,他被允许一个。然后我需要获得实际的折扣价,我会直接从公开方法 getCustomersPrice(customerid) 的产品中获得它。 最后,我会将两个收据项目添加到收据中。它们都具有相同的产品代码,但价格不同。 (如果限额为 2 件或更多,我只会以折扣价将一件元素添加到收藏品中,但算上 2 件)。
您认为这是一个好方法吗?我担心将产品作为输入参数传递给 addItem。因为它似乎产生了紧密的耦合。
谢谢。
最佳答案
Receipt
聚合根应该更小:Receipt
有 ReceiptItem
,这很好,但是 Customer
应该是它自己的聚合根。客户独立于收据而存在,最好是小聚合。
Product
也是此限界上下文中的单独域对象,即使产品也存在于单独的限界上下文中。 Product
也需要在 Receipt
聚合之外。
鉴于存在多个聚合根这一事实,将产品添加到收据的逻辑涉及多个聚合。因此,逻辑不能驻留在 Receipt
聚合或任何其他聚合内。这样的逻辑最好放在域服务
中(它可能与Receipt
聚合位于同一个包中),例如:
public class ReceiptService {
void addItem(ReceiptId aReceiptid, ProductId aProductId, int quantity) {
// business logic to determine price per item
// ...
// for each item, forward item creation to receipt:
receipt.addItem(productIdOrName, priceOfItem);
}
}
域服务结合各种聚合的数据以确定每件商品的价格。创建 ReceiptItem
并将其插入收据项目集合的内部逻辑最好转发到 Receipt
聚合。
关于domain-driven-design - DDD - 将项目添加到订单/收据时的价格计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58988791/