贫血领域模型是否意味着您不能将实用程序/支持类用作领域模型的“助手”?

5
根据此定义,Fowler的贫血领域模型概念是:

业务逻辑实现在领域对象之外的软件领域模型

而且

使用此模式时,逻辑通常是在单独的类中实现的,这些类可以转换领域对象的状态。Fowler将这样的外部类称为事务脚本。

如果我们以购物车为例,Cart对象将是领域对象。但是要将购物车处理到最终订单和收据需要检查订单库存并处理信用卡付款。很多事情都需要实用程序类,因为仅在Cart对象内部执行所有操作意味着Cart类会变得庞大而笨重。那么,这是否意味着在此示例中的Cart将是贫血领域模型,并且这些实用程序类将根据上述定义成为“事务脚本”?
2个回答

4
领域驱动设计的一个关键概念是创建一个丰富的设计,传达并反映其领域专家(业务用户)的行话。然后,您希望您的代码成为该领域模型的表达式。(请参见DDD Patterns summaries中的“普遍语言”和“模型驱动设计”)。
这样做时,您将为实体(类)创建名称,这些名称反映业务用户可能描述它们的方式。此外,您将在这些类上创建方法,这些方法也反映了该领域。
考虑到这一点,考虑如何思考您的“helper”或“utility”类可能会有所帮助。使用您的一些描述,您可能会有以下类和方法:
product = GetProduct(data.productId);
shoppingCart.add(product);
receipt = customer.Purchase(shoppingCart);

您的Customer.Purchase方法可能会执行以下操作:
creditCard = this.getCreditCart(creditCardNumber);
purchaseNumber = creditCard.Charge(shoppingCart.Total);

我意识到这些例子并不完整甚至不完全准确,但我希望这个想法能有所帮助。
回答你的原始问题——是的,拥有实用程序和支持类是可以的。然而,你需要创建这些支持类并将它们映射到真正的领域实体。经过与用户的一些工作后,你可能能够创建有意义的领域实体,这些实体不仅仅是交易脚本实体。
希望这有所帮助。祝好运!

1
请原谅我的好奇心,但我理解的问题是关于“贫血领域模型”,它完全禁止像上面的Purchase()这样的方法在领域类中使用。使用贫血领域模型,领域类除了getter/setter之外没有任何更多的东西,你最终会发现所有(!)的行为都是在领域类之外实现的。因此,在上述假设下,采用贫血领域模型将迫使您使用辅助/实用程序类,因为您别无选择!为什么不兼顾两者的优点:在领域模型中使用通用算法,其余部分则放在外部!斯特凡 - struppi
1
@struppi - 你为什么说像上面的Purchase()方法会被禁止?这个方法很可能不仅仅是获取/设置,因为它将包含执行购买的业务逻辑。 - Chris Melinn

1

正如Chris所说,如果这些支持类映射到从用户语言中发现的真实领域实体,则拥有实用程序和支持类是可以接受的。有时,“帮助类”很多是贫血模型的症状,如果它们与主要具有setter和getter的类相关(在这些情况下,帮助程序会从未正确分配给领域对象的行为中增长)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接