MVC:把业务逻辑放在哪里? [关闭]
Posted
技术标签:
【中文标题】MVC:把业务逻辑放在哪里? [关闭]【英文标题】:MVC: Where to put business logic? [closed] 【发布时间】:2013-09-04 23:21:16 【问题描述】:首先,我已经看到了很多关于这个的问题,但没有足够的理由支持。如果我的问题不够好,应该被删除,我会理解的。
例如,我查看了this,一个 45+ 投票的答案说他建议您将业务逻辑放入模型中,这听起来很合乎逻辑。
然而,我的第一个大型项目是我在控制器中完成的所有 BL,因为我没有质疑这些事情,而是在 AccountController
中查看了它是如何完成的,如果您选择 MVC表单认证。所有的方法看起来都充满了 BL。或者也许这是可以添加的最少代码量而我忽略了一些事情?
youtube 上的一个人通过将所有逻辑都放入他的模型中来问我他是否正确,起初我不是!然后我开始想,也许他是对的!?
那么,毕竟,我应该把我的业务逻辑放在哪里? 如果它是在模型类中,那么,在控制器中的方法中应该考虑多少代码是健康的?最多一行从控制器中的模型调用一些方法然后返回视图?
【问题讨论】:
业务逻辑进入控制器。模型逻辑进入模型。模型逻辑是专门/仅处理模型的事物。 Setter/getters/properties/adders/removers 等 @crush:我不同意。正如我所读到的 - “模型对象包含应用程序的数据和“业务逻辑”。“控制器对象将模型和视图对象联系在一起。” @BobbyDigital - 你能提供源链接吗? :) 当然,它在The Big Nerd Ranch Guide 中对正确使用 MVC 的解释中,但不幸的是,您必须购买这本书才能确认这一点。 我会说,刚刚尝试在 C# 书中确认这一点,在 asp.net 中,业务逻辑位于中间层,顶层是 UI,中间层是控制器底部是分贝。但他们并没有具体/明确地谈论 MVC。这来自C# for Programmers :) 【参考方案1】:出于几个原因,我更喜欢将领域逻辑放入模型中。
模型中应该没有 UI 代码,因此更容易测试。只要有可能,我喜欢在编写任何 UI 代码之前拥有一个完全工作(意味着完整的测试覆盖)的模型。控制器可以相信模型正在做正确的事情,并且只处理 UI 问题。
如果你将域逻辑放在一个控制器中,那么在不同的应用程序之间,甚至在不同的控制器之间共享都不是那么容易。
【讨论】:
是的,我真的很喜欢#2
,因为我发现自己很难在控制器之间共享(不得不使用静态等方法)!
是的@AndriusNaruševičius,不要那样做。您应该尝试将依赖项注入控制器,而不是依赖其他控制器。
请注意,我认为这个答案是关于“域模型”(经典 MVC 模式的 M 部分),这与 ASP.Net MVC“模型”(MVVM 模式的一部分)无关。跨度>
那么...你把依赖多个模型的逻辑放在哪里?
@Ferrucio 这是一个糟糕的解决方案。您最终会陷入“依赖地狱”,您创建的对象依赖于要创建的其他对象。这是一个糟糕的解决方案,因为无缘无故地传递了不必要的/未使用的数据。您希望函数只获取完成工作所需的内容 - 否则代码很快就会变得不清楚。更好的解决方案是创建最少构建的业务逻辑类(或者更好的是,使用依赖注入来构建)。这样一来,您永远不必获取几个不相关的对象来执行业务逻辑。【参考方案2】:
我喜欢保持模型干净,即只有属性,没有业务逻辑。我一直认为将依赖项注入控制器很好,这些依赖项包含我在模型上执行的逻辑。我喜欢尽可能坚持单一责任原则,我发现具有大量方法的模型很快就会变得臃肿。两者各有利弊,注入大量依赖项会产生开销,但允许单独测试并保持类简单,最终您将拥有更精简的控制器。尽管我的逻辑实际上并不作为班级成员存在于我的模型中,但它仍然是业务逻辑。我倾向于没有在控制器中定义业务逻辑,因为像 Httpcontext 这样的模拟有点像噩梦并且没有必要。
【讨论】:
+1 完全同意。我以为我是唯一一个喜欢把模特的责任降到最低的人! 当然,他是我的登录控制器gist.github.com/markwalsh-liverpool/8fb361a9df0dcf034caf的要点@ 如果你不把你的逻辑放在你的模型或控制器中 - 你把它放在哪里? 如何将参数传递给控制器的构造函数?控制器的初始化通常不是在幕后完成的吗? 我使用依赖注入。【参考方案3】:业务逻辑属于问题域,属于问题域的一切都进入MVC中的模型。
控制器应该负责将数据从模型传递到视图,然后从视图传回模型。因此,控制器是用户交互内容与程序如何建模和存储问题状态之间的桥梁。 管道,可以这么说。
这里的关键是业务逻辑和管道逻辑之间的区别。在我看来,自动生成的 Account Controller 所做的主要是管道,而不是真正的业务逻辑。请记住,管道逻辑并不一定很短,因此您无需强加人为限制(例如“控制器中最多调用 X 次”)。
【讨论】:
我同意这一切。但是,我认为很多困惑来自于如何在模型中构造类,尤其是 EF。 IE:您是否使用部分类并在不同的 C# 文件中构建逻辑?一个文件用于 EF,一个文件用于逻辑?【参考方案4】:围绕这个话题似乎有些混乱。大多数情况下,人们似乎倾向于将 MVC 模式与 N 层架构混淆为非此即彼的情况。现实情况是这两种方法可以一起使用,但一种不依赖于另一种,也不需要。
N 层架构涉及将应用程序分成多个层。一个简单的例子是将应用程序拆分为表示层、业务逻辑层和数据访问层。
MVC 是一种处理应用程序表示层的设计模式。完全可以按照 MVC 方法设计应用程序,而无需将业务逻辑和数据访问逻辑与表示层分离,从而最终得到单层设计。
如果您遵循 MVC 方法而不将应用程序分层,那么您最终会得到模型、视图和控制器,其中包含一些业务规则和数据访问逻辑与其余逻辑混合在一起.
根据定义,在 N 层架构中,表示层应该只能够与业务逻辑层通信,因此它应该认为任何 MVC 组件只能与业务逻辑层通信。
如果您正在构建一个不涉及表示的应用程序,因此不涉及表示层,那么您不必担心 MVC 模式。但是,即使不涉及表示层,您仍然可以将应用程序拆分为多个层,从而遵循 N 层设计。
【讨论】:
【参考方案5】:当我的团队从 webforms (asp.net) 迁移到 mvc 时,我进行了大量研究并提出了以下结构。在我看来,这与应用程序的大小无关。它是关于保持代码干净和清晰。
DALProject
AccountsDAL.cs --- > Calls SP or any ORM if ur using any
BLL项目
AccountsBLL.cs ---> Calls DAL
网络项目
Model
AccountsModel --- > Contains properties And call BLL
Controllers
IndexController ---> Calls Models and returns View
Views
Index
控制器应该负责模型和视图之间的数据传递。除此之外,不应该有任何不必要的代码。例如,如果您正在记录它应该在模型级别而不是控制器上完成。
【讨论】:
【参考方案6】:业务逻辑不应进入您的模型视图或控制器。应该有一个单独的业务逻辑层;该层的唯一目的是处理您的业务逻辑。这更符合SOLID。
如果您将业务逻辑放在 M V 或 C 中,您最终会得到难以测试/重用的代码。
将逻辑放在模型中怎么样?
这是一个糟糕的解决方案。
你最终会陷入依赖地狱,对象依赖于对象。
即使你有一个死的简单函数,你仍然必须满足所有依赖才能调用它。
它还会导致 unnecessary 和 unused 数据无缘无故地被传递。 这也可能会影响性能,具体取决于它的糟糕程度。
我还应该提到,单元测试在 a** 中变得很痛苦,因为您必须模拟多个对象来测试一个简单的函数。
适用的清洁代码原则
-
类/函数只使用完成工作所需的内容。
如果可能,函数应采用 3 个或更少的参数
智能地命名类/函数/变量(遵循 Microsoft 的标准)
不要将业务逻辑与模型视图或控制器耦合
控制器
在您的控制器中,您应该能够使用依赖注入来注入业务逻辑层。确保您的控制器仅用于将信息路由到业务逻辑层。 控制器中不应直接包含业务逻辑。任何验证都需要由模型上的IValidatable
处理。任何业务逻辑都需要路由到单独的层。
【讨论】:
在我工作的地方,我们有一个业务层,我只是希望我们没有它。业务层一团糟,逻辑应该在模型中。 @MateusFelipe 那么,你把需要多个模型的逻辑放在哪里(例如:支付和产品)?您是否创建了一个将Payment
和Product
作为实例变量的新模型?你给那个物体起什么名字?如果模型未在视图中使用,则它不再是模型。它是单独层的一部分。理想情况下,你制作的那个类应该只从 Payment 和 Product 中获取它需要的东西来完成它的工作。如果它只需要productName
和price
,它应该只接受这两个参数,而不是整个对象。
MVC 中的 M 传统上指的是“应用程序模型”,这只是表示“应用程序的整个其余部分”的一种简单方式,但除非您了解其余部分,否则这并没有真正的帮助。V在 MVC 中,传统上是指用户正在查看的内容,有时该视图在“ViewModel”类中建模,但这仍然意味着它在架构上是视图的一部分。C 是控制器,指的是代码库中控制流量的任何内容在应用逻辑请求和查看结果之间。“多模型”暴露了对 MVC 是什么的根本误解。【参考方案7】:
一般来说,业务逻辑不应该驻留在任何 MVC 播放器中;它应该仅由您的控制器操作使用。
正如许多人所提到的,最好创建一个库来将业务逻辑托管为一组与客户端无关的可重用组件。
通过这种方式,我们大大提高了软件的可重用性、兼容性、可扩展性和可测试性。我们还减少了对某些框架功能的依赖,从而更容易迁移到更新/不同的技术。
多年来,将我们的业务逻辑抽象为一个独立的程序集(或多个程序集)对我们很有帮助。然后,我们的业务逻辑几乎可以被任何 .NET 技术(ASP.NET MVC/API/Core、WPF、Win Forms、WCF、UWP、WF、控制台等)使用。
此外,我们喜欢我们的中间层来处理业务规则和验证逻辑,以减少我们对 .NET MVC 框架的依赖。例如,我们避免使用 .NET MVC 验证助手,而是依赖我们自己的。这是另一个让我们能够轻松使用任何 .NET 技术的业务逻辑的因素。
以这种方式逻辑设计我们的中间层使我们能够轻松实现这种物理架构:
它是用Peasy.NET 编写的,多年来一直为我们服务。事实上,我们决定开源它。
如果有人对我们的中间层是什么样子感到好奇,这里有一个与客户端无关的业务层的sample。它还展示了多个 .NET 客户端(ASP.NET MVC、Web Api 和 WPF)对它的使用。
希望这对某人有所帮助!
【讨论】:
大多数情况下不需要重用逻辑。如果我决定将 ASP.NET Core MVC 用于 Web API,我将永远不想在 WPF 或 WinForms 中使用该业务逻辑。因为客户端无论如何都会与服务器通信。将业务逻辑,尤其是数据库访问逻辑放在客户端是很糟糕的。 您添加的层数越多,我会说它会降低可维护性和可测试性。最后,集成测试更重要。【参考方案8】:我的一般答案是业务逻辑通常分为两类:
面向对象的业务逻辑:被建模为对象(在模型中),通常作为存储库注入。
程序化业务逻辑:进入具有可注入控制器的接口的服务。
控制器逻辑:控制如何接收命令并将其传递给模型/服务,然后如何将这些结果传递给视图的逻辑。
控制器不应该有业务逻辑,它是设计模式的一个非常具体的部分,用于控制用户界面如何将输入传递给处理业务逻辑的模型(或服务,如果您的问题本质上更程序化)。
【讨论】:
【参考方案9】:我也喜欢让我的模型保持干净(参考:@Mark Walsh)。无法重用嵌入在控制器中的逻辑的问题可以通过依赖注入轻松解决,或者,如果您认为其中过多,请通过接口公开您的业务/域逻辑并在控制器中使用外观模式。这样您就可以获得所需的功能,但同时保持控制器和模型的美观和整洁。
【讨论】:
【参考方案10】:我也希望保持模型干净。 MVC 控制器应仅用于进行调用,并且还应保持清洁。因此,根据其可重用性、敏感性和相关性,可以用
编写业务逻辑1.WebApi 控制器:使用 webapi 控制器的优点是您可以稍后将这些作为服务公开给其他设备,从而使您的代码可重用。
2。 BAL / Common commonent:有些逻辑有特定的用法,不能暴露为api,可以在这个类中推送。
3.存储库: 所有与数据库相关的查询都添加到存储库中。可以有一个通用存储库,它将为每个表实现所有功能(CRUD 操作)或特定存储库。取决于要执行的操作。
【讨论】:
【参考方案11】:正如 ahanusa 所写,您应该将业务逻辑放入单独的 DLL 或单独的目录中。 我经常在模型和控制器的同一级别使用一个名为 Logics 的目录,在其中放置执行业务逻辑的类。 通过这种方式,我让模型和控制器都清理干净。
【讨论】:
【参考方案12】:我知道这是一个关于 MVC 的问题,但我认为我给出的示例(Web API)会很有用。
我正在开发我的第一个 Web API,并且我正在重用来自其他应用程序的业务逻辑。具体来说,它来自外部 DLL,因此我的 API 仅用于与 SAP 解决方案“对话”,接收来自 PO 的请求并发送回响应。
如何将我的逻辑(已经实现)放入我的控制器中?我不需要它。我的控制器只会接收、验证请求并编写响应以发回数据。
我正在使用 ViewModel 类,它们必须有一个映射函数,只是为了从 TransferObjects(来自外部 DLL)读取信息并转换为 ViewModel。
我对我的应用程序(在本例中为 Web API)持有业务逻辑感到不舒服,我认为这样会失去可重用性。
我将我的业务逻辑视为我注入控制器的依赖项。
为了提供可单元测试的解决方案,我在旧版中进行了大量重构,我必须创建大量接口并在旧版中实现一些设计模式才能提供此解决方案。
在我看来,业务层必须是应用程序的一部分,最好是在另一个类库中。因此,您将在您的应用程序中实现真正的分离概念。
当然,如果您的 CORE(业务)是您的应用程序(API/WebSite),则业务规则将在您的 MVC 类中实现。但是将来如果你想开发一个新的应用程序并且一些业务规则是相同的,我敢打赌你会遇到很多问题,只是要在两个应用程序中实现相同的逻辑。
【讨论】:
以上是关于MVC:把业务逻辑放在哪里? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章