【问题标题】:Where does the "business logic layer" fit in to an MVC application?“业务逻辑层”在哪里适合 MVC 应用程序?
【发布时间】:2011-06-01 17:29:41
【问题描述】:

首先,在有人大喊大叫之前,我很难用一个简单的标题来概括它。另一个标题可能是“领域模型和 MVC 模型有什么区别?”或“什么是模型?”

从概念上讲,我理解模型是视图和控制器使用的数据。除此之外,对于模型的构成似乎有很多不同的意见。什么是领域模型、应用模型、视图模型、服务模型等等。

例如,在我最近问及存储库模式的一个问题中,有人直接告诉我存储库是模型的一部分。但是,我阅读了其他意见,认为模型应该与持久性模型和业务逻辑层分开。毕竟,存储库模式不应该将具体的持久性方法与模型分离吗?其他人说域模型和MVC模型之间存在差异。

让我们举一个简单的例子。 MVC 默认项目中包含的 AccountController。我已经阅读了一些意见,其中包含的帐户代码设计不佳,违反了 SRP 等等。如果要为 MVC 应用程序设计一个“适当的”会员模型,那会是什么?

您将如何将 ASP.NET 服务(成员资格提供程序、角色提供程序等)与模型分开?或者你会吗?

在我看来,模型应该是“纯粹的”,可能带有验证逻辑......但应该与业务规则分开(验证除外)。例如,假设您有一条业务规则,规定在创建新帐户时必须向某人发送电子邮件。在我看来,这并不真正属于模型。那么它属于哪里呢?

有人愿意解释这个问题吗?

【问题讨论】:

  • 这就是为什么你应该问四个不同的问题。
  • 关键字是“几乎”。这实际上是同一个问题,可能使用子问题来说明主要问题。
  • 模型 - 视图 - 控制器。是存储库/BL 视图吗?不,是控制器吗?不。还剩下什么:)?它是 MVC,不是 MSVC,不是 MRVC,不是 MBLVC。只有三层。所以存储库是模型的一部分,BL 是模型的一部分。您可以进行额外的分离,但它是在模型层内部完成的。
  • @LukeLed, @bslm - 不是真的。 MVC 并没有说控制器或模型不能与其他层交互。
  • @LukLed - 不同意 - MVC 只是一种表示层模式。它不会影响您如何构建 BLL 和 DAL 等其他层。

标签: asp.net-mvc model-view-controller design-patterns business-logic-layer


【解决方案1】:

我经常想知道 MVC 元素究竟如何适合传统的 Web 应用程序结构,在这种结构中,您拥有视图(页面)、控制器、服务和数据对象(模型)。正如你所说,有很多版本。

我认为存在混淆是因为上述广泛接受的架构,它使用“贫血域模型”(据称)-反模式。我不会详细介绍贫血数据模型的“反模式”(您可以查看我的努力来解释 here(基于 Java,但与任何语言相关))。但简而言之,这意味着我们的模型只保存数据,业务逻辑放在服务/管理器中。

但是让我们假设我们有domain driven architecture,并且我们的域对象是它们所期望的方式——同时具有状态和业务逻辑。从这个领域驱动的角度来看,事情已经到位:

  • 视图就是 UI
  • 控制器收集 UI 的输入,调用模型上的方法,并向 UI 发送回响应
  • 模型是我们的业务组件 - 保存数据,但也有业务逻辑。

我想这回答了你的主要问题。当我们添加更多层时,事情会变得复杂,比如存储库层。通常建议它应该由放置在模型中的业务逻辑调用(因此每个域对象都有对存储库的引用)。在我链接的文章中,我认为这不是最佳实践。事实上,拥有一个服务层并不是一件坏事。顺便说一句,领域驱动设计不排除服务层,但它应该是“瘦”的,并且只协调领域对象(因此没有业务逻辑)。

对于被广泛采用(无论好坏)的贫乏数据模型范式,该模型既是服务层又是您的数据对象。

【讨论】:

  • 好点!一句话:服务也有同样的混乱。至少服务可以是应用程序服务和域服务。应用程序服务只是一个瘦包装器,它从存储库等收集信息。域服务提供业务逻辑,即使用域模型的组合或仅使用不总是适合域模型的东西。
  • 如果您的项目没有数据库怎么办。它与服务引用交互。所有域类和方法都来自这些引用。这种场景适合分层结构吗?
【解决方案2】:

我这样做的方式——我并不是说这是对还是错,是拥有我的视图,然后是一个适用于我的视图的模型。该模型仅包含与我的视图相关的内容 - 包括数据注释和验证规则。控制器仅包含用于构建模型的逻辑。我有一个包含所有业务逻辑的服务层。我的控制器调用我的服务层。除此之外是我的存储库层。

我的域对象是分开存放的(实际上是在他们自己的项目中)。他们有自己的数据注释和验证规则。我的存储库会先验证域中的对象,然后再将它们保存到数据库中。因为我的域中的每个对象都继承自内置验证的基类,所以我的存储库是通用的并验证所有内容(并要求它继承自基类)。

您可能认为拥有两组模型是重复代码,并且在一定程度上是重复的。但是,在某些完全合理的情况下,域对象不适合视图。

以使用信用卡为例 - 我在处理付款时必须要求提供 cvv,但我无法存储 cvv(这样做会被罚款 50,000 美元)。但是,我还希望您能够编辑您的信用卡 - 更改地址、姓名或到期日期。但是你不会在编辑时给我号码或 cvv,我当然不会把你的信用卡号码以纯文本形式放在页面上。我的域具有保存新信用卡所需的这些值,因为您将它们提供给了我,但我的编辑模型甚至不包括卡号或 cvv。

这么多层的另一个好处是,如果架构正确,您可以使用结构映射或其他 IoC 容器并交换部分,而不会对您的应用程序产生不利影响。

在我看来,控制器代码应该只是针对视图的代码。显示这个,隐藏那个,等等。服务层应该包含应用程序的业务逻辑。我喜欢将所有这些都放在一个地方,以便轻松更改或调整业务规则。存储库层应该相对笨拙——没有业务逻辑,只查询您的数据并返回您的域对象。通过将视图模型与域模型分离,您在自定义验证规则方面拥有更大的灵活性。这也意味着您不必将每条数据都转储到隐藏字段中的视图中,并在客户端和服务器之间来回推送(或在后端重新构建)。然后,您的视图模型将仅包含与视图相关的信息 - 并且可以对其进行自定义以具有用于视图逻辑或计数或枚举的布尔值,以便视图本身不会被复杂的逻辑语句(如

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

虽然所有内容看起来都分散且分层,但以这种方式构建它是有目的的。完美吗?并不真地。但我确实更喜欢它,而不是过去从控制器调用存储库并将业务逻辑混合在控制器、存储库和模型中的一些设计。

【讨论】:

  • 只是我在企业 MVC 应用程序中的镜像。 N 层架构。 MVC 应用仅与 N 层区域中的业务对象和服务交互。
  • 这里大体相同。用于定义、模型、视图模型、DAL 等的单独项目。唯一的区别是我的 DAL 包括为 Web 展平数据的逻辑,以优化报告或自定义客户视图的复杂数据的分布。我现在回避在应用程序缓存中保存查找表等内容,使用 Web 农场和 Azure 云。
  • @Josh,如果您能显示示例项目的屏幕截图会很有帮助?
  • @Josh 如果您的项目没有数据库怎么办。它与服务引用交互。所有域类和方法都来自这些引用。这种场景适合分层结构吗?
【解决方案3】:

MVC 模式和 Asp.net 框架对模型应该是什么没有区别。

MS 自己的示例包括模型中的持久性类。您关于模型中的成员资格的问题。这取决于。模型中的类是否归某物所有?谁登录和显示什么数据之间有联系吗?是否过滤了可编辑的权限系统的数据部分?谁最后更新或编辑了您域中的对象部分,因为其他人需要查看它或后端支持?

电子邮件示例也取决于它。您是否熟悉域事件或特别是事件?您有单独的服务来发送电子邮件吗?发送电子邮件的行为是您域的一部分,还是您系统范围之外的应用程序级别问题? UI 是否需要知道电子邮件是否发送成功?发送失败的邮件是否需要重试?是否需要存储发送的电子邮件内容以满足支持或客户服务需求?

这些类型的问题过于宽泛和主观,但我正在回答,以便您和投票给您的每个人都能理解这一点。

您的需求/时间表/资源都融入了您的系统架构。甚至revenue model 也会产生影响。您还必须考虑要拍摄的模式。 DDD 与持久化模型应用程序有很大不同,两者之间的所有差异也适用于某些应用程序。您是在为测试应用程序而拍摄吗?所有这些都会产生影响。

【讨论】:

    【解决方案4】:

    在我看来,

    型号 -

    不应包含业务逻辑,它应该是可插拔的(WCF 类场景)。它用于绑定到视图,所以它应该具有属性。

    业务逻辑 -

    它应该放在“域服务层”,它完全是一个单独的层。 此外,将在此处添加一层“应用程序服务”。

    应用服务与域服务层对话以应用业务逻辑,然后最后返回模型。

    所以, 控制器将向应用程序服务询问模型,流程会像这样,

        Controller->Application Services(using domain services)->Model
    

    【讨论】:

      猜你喜欢
      • 2011-12-26
      • 1970-01-01
      • 2013-04-01
      • 1970-01-01
      • 2011-04-20
      • 2011-05-30
      • 2013-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多