ASP.NET MVC中的业务逻辑:领域模型 vs 服务层

37

我一直在阅读关于在ASP.NET MVC项目中放置业务逻辑的问题,但仍然有些事情不太清楚。

1- 领域模型。这些到底是什么?在我的Model文件夹中,我只有一堆对应数据库的类。我正在使用EF Code First。我假设这些是我的领域模型。

2- 服务层这个答案建议使用服务层,我认为这非常有道理。我已经决定采用这种方法。然而,Martin Fowler的“贫血领域模型”文章使我感到困惑。

我真的不确定如何将逻辑添加到我的领域模型中。

我已经阅读了许多与业务逻辑相关的问题,每个问题都提出了1或2种方案。我不明白的是,我如何实现第一个方案。将方法添加到实体类(对我来说就是领域模型)根本没有意义。为什么第二种方法被认为是不好的?

5个回答

28

首先,你在 Asp.Net MVC 项目中的 Model 文件夹应该用于 ViewModels。这些模型是 Controller 发送到 View 的模型。它们应该针对 View 进行高度优化,即仅包含 View 需要的属性,而不包含其他内容。

你所说的 Domain Models 与 Business Models 相同,应该放在 Business 层中。Asp.Net MVC 项目中的 Model 文件夹是 UI 层的模型。

第二种方法,在 Service(实际上是 Business)层中处理业务逻辑并不被认为是不好的。它是数据层和 UI 层之间的非常好的缓冲区(3 层架构)。数据层处理获取数据,可以是来自 Web 服务或数据库,业务/服务层处理将该数据转换为 Business/Domain 模型。它还包含任何业务逻辑,例如计算等。

这些 Business/Domain 模型通常是 POCO,但不必如此。这是我有时设置我的 Business Models 的方式:

public class BusinessObject
{
    private DataObject _dataObject;

    public BusinessObject(DataObject dataObject)
    {
        _dataObject = dataObject;
    }

    public int BusinessId
    {
        get {return _dataObject.Id;}
        set {_dataObject.Id = value;}
    }

    public string Name
    {
        get {return _dataObject.Description;}
        set {_dataObject.Description = value;}
    }
}

1
谢谢。我有一个ViewModel文件夹用于我的视图模型,但我理解你的观点。只是想澄清一下,BusinessObject中的DataObject是实际映射到我的数据库的类吗?(在我的情况下是Ef实体) - emre nevayeshirazi
BusinessObject 是您的领域模型,而 DataObject 则是您数据层中的一个类 - 在您的情况下,它是您的 EntityObjects 之一。 - Martin
非常感谢您。您澄清了我头脑中大部分困惑的事情 :) - emre nevayeshirazi
为什么要在BusinessObject中保留底层的DataObject,而不是使用您提到的POCO和一个非常简单的映射方法public static BusinessObject ToBusinessObject(this DataObject dataObject) { return new BusinessObject { BusinessId = dataObject.Id, ... }; } - ErikE

14

我不希望在领域模型中有业务逻辑。通常情况下,我会将我的领域模型保持为POCO,以表示我的数据库表/模式。

将业务逻辑与领域模型分离将使我能够在另一个项目中重用我的领域模型。

您可以考虑在控制器和数据访问层/存储库层之间添加中间层来处理此问题。我将称之为服务层。


7
您的领域模型是一个没有功能的独立程序集,这一点需要澄清吗?这不是贫血领域模型反模式吗? - Josh Noe
这些是POCOs。我可以在任何地方/项目中重复使用它们。 - Shyju
3
是的,它们是POCOs(Plain Old CLR Objects),但它们并不是传统意义上的“领域模型”。它们是数据库的内存表示。不是说它们没有用处,只是更适合作为数据传输对象而不是领域对象。参见:http://martinfowler.com/eaaCatalog/domainModel.html - Josh Noe
1
我对贫血模型和领域模型感到非常困惑。因为你的耦合度越低,你的模型就会越贫血。而且业务规则可能因公司而异。但我不明白,为什么贫血模型是不好的。以及应该将哪些行为放在领域模型和领域服务中。 - Jaime Sangcap
@Daskul - 贫血模型不好的原因之一是因为你没有充分利用面向对象的优势(对象应该包括行为,而不仅仅是数据)。领域模型中的行为应该与您定义的核心业务实体直接相关。服务层包括与业务对象无直接关系的行为,例如执行与多个业务对象相关的操作,或者执行不适合您的业务对象的操作,例如使用从外部源接收到的数据填充业务对象等。 - BornToCode

10

我知道这个问题已经有答案了,但是我把模型分为三类。

ViewModels - 这些是轻量级(通常是 poco)的类,用于模拟网站页面所需的数据。这些类处理用户所看到的基本信息,并在要显示的数据发生更改时进行更新。

DomainModels - 这通常是重型业务逻辑类。它们通常模拟您正在做的核心业务规则。这些类通常高度内聚,并且是使您的网站变得特别的大部分工作发生的地方。我说这些模型通常是重量级的,但实际上,如果您的项目只是从用户那里获取数据并将其放入数据库中,则该类将是一个小型数据映射类。很多时候,您会看到这些类由持久化模型组成并返回视图模型。

PersistenceModels - 这些是持久性机制的模型。对于我们大多数人来说,这意味着建模数据库表,但也可能是复杂的非关系型文档或从 API 请求返回的 json(或其他)数据。它们的责任是处理外部数据的格式。

还要记住,您不总是需要在项目中使用这三种类型的模型。有时您的视图模型将与您的持久化模型一一对应。在这种情况下,编写整个程序两次并添加一个域模型来进行映射是浪费客户的钱。作为开发人员,您的工作是知道何时建立航空母舰去商店买菜。


2

领域模型应该能够独立完成其工作,并公开代表其状态和功能的属性和方法。它们充当信息层次结构(聚合根)中必需的模型的根,仅对服务可用。

服务将业务/领域功能暴露给外部世界(Web服务、UI等),作为遵循消息模式(请求/响应)的API集合,通过从封装数据访问层的存储库中检索模型,然后调用模型的方法/业务函数并最终将其保存回存储库来实现。

有时会感觉服务重复了业务对象的方法,但在时间和实践中,这并不是真正发生的情况。

在真正的领域驱动设计中,您至少需要三套对象:业务对象、业务对象的存储库和服务。

想象一下,如果每种类型的组件都由不同的团队编写,则要求一个暴露的服务,而不必知道详细信息,也不必在服务本身上编写逻辑。然后,任何需要它的人都可以消费该服务,而无需深入挖掘核心模型本身。


-1

应用程序的流程控制逻辑应该放在控制器中。

数据访问逻辑应该放在存储库中。

验证逻辑应该放在服务层中。

服务层是 ASP.NET MVC 应用程序中的另一层,用于在控制器和存储库层之间进行通信。

服务层包含业务验证逻辑。

例如,产品服务层有一个 CreateProduct() 方法。

CreateProduct() 方法调用 ValidateProduct() 方法,在将产品传递到产品存储库之前验证新产品。

来源: http://www.asp.net/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs


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