胖模型/瘦控制器与服务层[关闭]
Posted
技术标签:
【中文标题】胖模型/瘦控制器与服务层[关闭]【英文标题】:Fat model / thin controller vs. Service layer [closed] 【发布时间】:2012-02-02 20:41:24 【问题描述】:多年来,我一直在使用 .Net 开发企业应用程序 我的应用程序通常有一个域模型,其中包含映射到 SQL 数据库表的实体。 我使用存储库模式、依赖注入和服务层。
最近我们开始从事 MVC 3 项目,我们曾争论将哪个逻辑放在哪里。 我遇到了瘦控制器/FAT 模型架构,想知道服务层如何适应
选项 1 - 模型与服务对话
控制器很瘦,在模型上调用方法。模型“知道”如何从数据库中加载自己并与存储库或服务通信。 例如。 customerModel 有一个 Load(id) 方法并加载客户和一些子对象,例如 GetContracts()。
选项 2 - 控制器与服务对话
控制器要求服务检索模型对象。加载/存储等逻辑在服务层。该模型是纯实体模型,仅包含数据。
为什么选项 1 是一个更好的选择,尤其是当我们谈论企业应用程序时,我的经验告诉我要分离关注点,保持模型和控制器尽可能精简,并让专门的服务来处理业务逻辑(imcl。数据库交互)
感谢所有建议和对优质资源的参考。
【问题讨论】:
【参考方案1】:所有这些都取决于您的应用程序的意图和要求。
也就是说,这是我对“中等规模”(不是本地餐厅,也不是 Twitter/Facebook)网络应用程序的建议。
精益领域建模
干式 POCO 样式对象,最好不了解您的 Web 应用程序的 MVC 架构,以尽可能与您的特定实现保持松散耦合。甚至可以重新打包类库以在外部应用程序中使用,例如通过 REST API WCF 网络服务)。
MVC 中的“模型”最准确地表示Controller 知道的模型,因此用于视图的模型。
在较小的(通常是教程)应用程序中,“应用程序/域模型层”的实体模型通常是控制器发送到视图的相同实例化对象。
在较大的应用程序中,开发人员通常采用 MVVM 架构的原则并开始使用单独的视图模型对象。控制器通常调用与下面看不见的实体一起工作的中间层服务。在这种情况下,MVC 中的 M 最准确的意思是 View Model。
强大的服务层
这并不意味着 肥胖 逻辑,而是精心编写的单一用途服务。虽然在模型之外的服务中编码业务逻辑比纯粹的“OOP”更“程序化”,但它对松散耦合、测试和灵活部署(例如 n 层部署)有很大帮助。
在我的个人实践中,我在数据层对服务进行编码,我认为我对 POCO 对象的行为建模(持久性机制、低级别验证等)和更高级别的服务(业务/工作流功能)更接近 MVC 机制。
精益控制器
我确保我的控制器只是 教练,因为它既不是 play(服务)也不是 player(实体模型或视图模型),但只是决定谁扮演什么位置以及扮演什么角色。我的控制器做了两件事:
调用与实体/域模型交互的服务
为适当的视图准备一个视图模型。
即使是经过身份验证/授权的控制器操作也是通过注入的服务/属性来完成的。
编辑 1:
请记住,这并不意味着您的实体/域模型是或必须是贫血的。欢迎使用 ORM、存储库和工厂、验证或状态机制。这仅意味着对于中等规模的应用程序,MVC 中的 Model 代表 用于控制器的模型,以移交给您的 View。
希望这一点能够让相信 贫血数据模型 是一种反模式 的 Fowler 使徒们平静下来。同时,它确实反映了比 OOP 稍微更程序化的角度,后者更纯粹地将行为包含在建模类中。
没有“终极真理”,但使用这种模式,您会发现很容易构建、测试和部署您的应用程序 - 同时保持大量的可重用性和可扩展性。
编辑 2:
也就是说,即使对于规模适中的应用程序,过度架构(书呆子组成的词?)系统也太常见了。例如,用存储库模式包装 ORM,然后编写服务以使用存储库......所有这些都有助于关注点分离等,但如果您的项目不需要(并且不太可能 很快需要)这样的东西,不要建造它。一起跳过存储库,针对 ORM 编写瘦业务服务(例如查询类),甚至让您的控制器直接与它对话都没有错。这一切都取决于规模。
编辑 3:
我想指出,这个解释和建议是针对像 ASP.Net 这样的服务器端 MVC 架构的上下文,而不是针对像 Knockout 或 Backbone 这样的客户端框架。
【讨论】:
这几乎与我使用的设计模式完全相同,只是控制器不了解存储库。控制器只与服务交互,而服务又与存储库交互。 @Lester 我编辑了它以清除它。我的 95% 的时间也没有,我的想法是服务可以。在小型应用程序上,它可能有点矫枉过正,但它是任何人的好习惯,并且使用 IoC 容器更容易维护 +1 @one.beat.consumer:这与我在项目中采用的方法相同......有时对规则过于纯粹会导致解决方案过于复杂,您可以体验到更多受益于不完全遵循 GOF 模式的经过实际验证的解决方案 @ivowiblo MVC 中的模型是您的控制器准备并传递给视图的任何数据模型。 这就是为什么您的“应用程序模型”(域模型、模型层等等—— you-label-it) 可以完全不知道 MVC 库,甚至存在于您的解决方案之外的单独分布式系统上。在 MVC 中,请求只是简单地路由到控制器。控制器组装视图模型(表示层的数据)。如果该模型与您在持久性机制中使用的实例化对象相同,则可能是不好的做法,但它是允许的,这意味着没有唯一的定义。 +1 for 请记住,MVC 中的“模型”最准确地表示 Controller 知道的模型,因此是用于 View 的模型。【参考方案2】:选项 2 被描述为 Fat Stupid Ugly Controllers 架构 (Reference to author of this expression)。这种解决方案通常违背 MVC 精神,因为它破坏了关注点分离。
【讨论】:
如果你问我,public ActionResult FetchApple() return View(_groceryService.GetApple("Granny Smith"));
非常精简。
我对那篇 FSUC 文章的阅读与上面的选项 2 不符。 FSUC 作者提供的示例没有显示使用封装了所有排序逻辑的服务层。相反,它显示控制器已经加载了业务逻辑。并且业务逻辑的可重用性,由于在控制器中,现在已经丢失了。【参考方案3】:
在我们继续讨论将所有内容放在哪里之前,您需要进一步了解 MVC。好吧,如果你想遵循这个模式。否则你现在可以停止阅读。
模式的定义非常松散。没有任何东西说明控制器、视图或模型应该是什么样子或者它们应该如何构造。该模式只是说明您应该分离各个部分以及它们应该如何相互交互。因此,让我们进一步了解它们是什么(我的解释)。
MVC
型号 模型可以是任何东西。它可以是 Web 服务、您的存储库、您的服务类或只是您的域模型。模型是用于获取所需信息的一切。将“模型”视为一个层,而不仅仅是一个对象。
控制器 控制器是胶水。它从模型中获取信息并使其适应视图,反之亦然。
查看 视图应该只呈现用户看到的内容。
请注意,您不应将模型与视图模型混淆。微软确实应该将“模型”文件夹命名为“ViewModels”,因为它们就是这样。我不会直接在视图中使用来自“模型”的信息。如果不这样做,则意味着您必须在视图更改时更改模型,反之亦然。
答案
模型不是视图模型而是层。模型中的所有内容都用于获取视图所需的信息。控制器获取该信息并将其放入单个视图模型中。
单个控制器操作可能会使用一次或多次调用“模型”来组装视图所需的信息。
这意味着如果您想获得一个易于维护和扩展的应用程序,您的第二个选项是最正确的。
请注意,可能不需要服务层。您可以直接从控制器调用 OR/M。但是,如果您发现自己在重复代码或获得胖控制器,只需将逻辑移至服务层即可。由于您使用的是正确的视图模型,因此只有控制器会受到该更改的影响。
【讨论】:
我希望 ASP.NET MVC 被命名为 ASP.NET ModelView View Controller。这将是一个可怕的名字,但至少它会传达它的真正含义:) 即使在使用 ASP.NET MVC 之后,我也花了一段时间才意识到模型并不意味着视图模型。 @one.beat.consumer:我对模型的看法是它可以是任何东西。它只是外面的一层。根据应用程序创建它。我这么说是因为很多人认为 ASP.NET MVC 中的 Model 是 View Model 或者 VM 和 Model 是一样的。 我确实认为我解决了这个问题。正如他在问题中谈到的那样,我对customerModel
的解释是视图模型。如果他明白事实并非如此,那么答案就更明显了。
@jgauffin 语义在这里很重要——在 MVC 中“模型”不暗示“模型层”;它only 意味着适合控制器传递给视图的模型对象。在大型应用程序中,MVC 架构通常甚至不知道模型/数据层或您选择的任何名称。我编辑的答案试图解释这种混淆......主要是当应用程序很小时,通常不需要额外分离模型和视图模型,因此人们倾向于标记他们的模型并让控制器使用存储库等。全尺寸应用,这种情况很少会发生。【参考方案4】:
选项 1: 你可以认为模型 == 服务。 模型也是业务层。
选项 2 是贫血域模型反模式。 http://en.wikipedia.org/wiki/Anemic_domain_model
【讨论】:
请记住,将某些东西称为反模式需要更多上下文!很多应用程序不需要域模型,因为它们做的大部分事情都是 CRUD 操作。 域模型只是一个带有“元数据”的数据,如果你没有元数据,那也没关系。我删除了“反模式”这个词,因为你在这方面是对的。我真的很喜欢接受的答案,而我自己的答案应该是评论。以上是关于胖模型/瘦控制器与服务层[关闭]的主要内容,如果未能解决你的问题,请参考以下文章