我应该将计算逻辑放在实体还是业务层中?


15

最近,我面临一个问题,即是否应在实体层中进行简单的计算,或者该实体是否应仅用于存储原始数据并将计算逻辑保留在业务层中。

所以我的问题是,在实体类的属性中封装简单的计算是否明智?

Answers:


21

这取决于您想要的体系结构类型。

  • 在域驱动设计中,您将创建一个具有数据和功能的域模型

这意味着Order拥有一个属性(或方法),该属性(或方法)将基于返回返回订单的总价OrderLines。该Order也将有一个方法AddOrderItem(Product product, int amount)Order将检查是否已经是一个存在OrderLine于该特定产品。

在这种模型中,您还将拥有不是真实实体的对象,例如Repository用于访问数据或Factory用于创建实体的对象。这些称为域服务。应用层负责调用域服务(例如,从数据库中检索实体),然后它将在该实体上执行功能。所述Application Layer应尽可能地薄。

这是一篇有关DDD的不错的文章,其中详细介绍了这些概念。

  • 您还可以使用Anemic域模型。这意味着您的实体由获取/设置属性组成,并且不包含任何行为。在这样的设计中,您的业务层将包含行为,例如计算Order价格和检查重复项OrderLines

对于Anemic域模型是否是一件坏事,存在不同的意见。我个人更喜欢真实的域模型。

本文介绍了贫血域模型和非贫血域模型之间的区别。


嗨,伍特,谢谢您的回答和链接。我似乎面对一个错误的想法,那就是当使用Anemic域模型时,所有业务逻辑(甚至是非常简单的业务逻辑)都应放在业务层中。在某些情况下,业务逻辑实际上仅取决于模型本身,这似乎是无稽之谈。例如,根据模型中的现有属性来计算属性。我找不到将所有取决于模型本身的业务逻辑放入业务层的明智原因。

在贫血的领域模型中,由于我们既有业务类又有实体类,如何正确命名类以避免它们之间的混淆?您是否建议使用后缀?如果是,您能举个例子吗?
夸德兹

对于DDD,如果价格计算逻辑复杂,该怎么办?例如,价格基于位置(税),用户信息(生日折扣,会员折扣),优惠券,信用卡(信用卡特别折扣)等。我们如何将此类逻辑放入Order类中?
Sher10ck

1
您的订单汇总应包含进行计算所需的所有这些信息。因为根据您的描述,这实际上应该是聚合的一部分。但是,如果逻辑变得非常复杂,您可能需要更改它,那么我会将计算器作为对象传递给实体构造函数,并让实体在内部使用计算器来设置价格。
burzum

贫血 ...听起来像是在患某种疾病。你不愿意被驱动吗?是的
马特·詹金斯

1

好吧,实体和业务对象在大多数情况下几乎是相同的。例如,如果您有一个产品类,并且想要公开一个属性,该属性将使用产品类中的某些现有属性并进行一些计算,然后将其公开。用这个术语说,创建该属性的逻辑仍然在类中是很好的。

现在,问题可能出在哪里,以适合您的业务层类。我更喜欢使用具有一些逻辑来处理业务问题的业务层类。例如,在您的“产品”示例中,业务问题可能是使用第三方供应商(如Paypal)向您收取费用。

要记住的关键一件事是,实体始终具有标识,而业务对象是没有标识的实体。例如,产品是一个实体,但是金钱没有身份。1000个不同的货币实例将是相同的。


是。如果该属性的业务逻辑全部取决于同一模型上的现有属性,则最好在模型中添加该属性。这将有助于减少不必要的业务层与计算出的属性的耦合。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.