胖模型/瘦控制器与服务层

Pet*_*gne 78 architecture model-view-controller asp.net-mvc service-layer asp.net-mvc-3

我使用.Net开发了多年的企业应用程序我的应用程序通常有一个包含映射到SQL DB表的实体的域模型.我使用Repository模式,依赖注入和服务层.

最近我们开始研究MVC 3项目,我们讨论了在哪里放置哪些逻辑.我来自瘦控制器/ FAT模型架构,并想知道服务层如何适应

选项1 - 模型与服务的对话

控制器很薄,调用模型上的方法.模型"知道"如何从数据库加载自己并与存储库或服务进行通信.例如,customerModel有一个Load(id)方法,并加载客户和一些子对象,如GetContracts().

选项2 - 控制器与服务对话

Controller要求服务检索模型对象.加载/存储等逻辑在服务层中.该模型是仅具有数据的纯实体模型.

为什么选项1会成为更好的选择,特别是当我们谈论企业应用时,我的经验告诉我要分离问题,让模型和控制器尽可能地薄,并且有专门的服务来做业务逻辑(imcl.数据库交互)

感谢所有建议和对优质资源的参考.

one*_*mer 90

所有这些都取决于您的申请的意图和要求.

也就是说,这是我对"中等规模"(不是本地餐馆,而不是Twitter/Facebook)网络应用程序的建议.

  1. 精益领域建模

    干POCO样式对象,最好是对Web应用程序的MVC体系结构无知,尽可能保持与特定实现的松散耦合.甚至可以在外部应用程序中重新使用类库,例如通过WCF Web服务的REST API ).

    MVC中的"模型"最准确地表示Controller所知道的模型,因此意味着用于View的模型.

    在较小的(通常是教程)应用程序中,"应用程序/域模型层"的实体模型通常与控制器发送到View的实例化对象相同.

    在较大的应用程序中,开发人员通常使用MVVM体系结构的原则,并开始使用单独的View Model对象.控制器通常调用与下面看不见的实体一起使用的中间层服务.在这种情况下,MVC中的M最准确地表示视图模型.

  2. 强大的服务层

    这并不意味着肥胖的逻辑,而是写得很好的单一目的服务.虽然在模型之外的服务中编写业务逻辑比纯粹的"OOP"更具"程序性",但它对松散耦合,测试和灵活部署(例如n层部署)有很大帮助.

    在我的个人实践中,我在数据层编写服务,我认为我对POCO对象的行为建模(持久性机制,低级别验证等),以及更高级别的服务(业务/工作流功能)更接近于MVC机制.

  3. 精益控制器

    我确保我的控制器仅仅是教练,因为它既不是游戏(服务)也不是玩家(实体模型或视图模型),而只是决定谁扮演什么位置以及扮演什么角色.我的控制器做两件事:

    1. 调用与实体/域模型交互的服务

    2. 为适当的视图准备视图模型.

    甚至通过注入的服务/属性完成经过身份验证/授权的控制器操作.


编辑1:

请记住,这并不意味着您的实体/域模型是或必须是贫血.ORM,存储库和工厂,验证或状态机制是受欢迎的.它仅仅意味着对于中等规模的应用程序,该型号在MVC代表的意思为控制器模式,移交给你的视图.

希望这一点能够让那些认为贫血数据模型成为反模式的福勒使徒们平静下来.同时,它确实反映了比OOP稍微更具程序性的角度,其中在建模类中包含行为更加纯粹.

没有"终极事实",但使用这种模式,您会发现构建,测试和部署应用程序变得容易 - 同时保持了大量的可重用性和可扩展性.


编辑2:

也就是说,即使对于规模适中的应用程序,过度架构(一个单词书呆子组成?)系统也是如此常见.例如,使用存储库模式包装ORM,然后编写服务以使用存储库......所有这些都有利于分离关注点等,但如果您的项目不需要(并且很可能不会很快需要) )这样的事情,不要建立它.一起跳过存储库,针对ORM编写瘦业务服务(例如查询类),甚至让控制器直接与它对话,也没有错.这一切都取决于规模.


编辑3:

我想要注意的是,这个解释和建议是针对像ASP.Net这样的服务器端MVC架构的上下文,而不是针对像Knockout或Backbone这样的清晰边框架.

  • 这几乎与我使用的完全相同的设计模式,除了控制器不知道存储库.控制器仅与服务进行交互,而服务又与存储库进行交互. (10认同)
  • @ivowiblo**MVC中的模型是控制器准备并传递给View的任何数据模型.**这就是为什么你的'应用程序模型'(域模型,模型层,无论你是什么标签)都可以完全不知道MVC库,甚至存在于单独分布式系统上的解决方案之外.在MVC中,请求简单地路由到控制器.控制器组装视图模型(表示层的数据).如果该模型与您在持久性机制中使用的实例化对象相同,那么可能会使用不好的实践,但*允许*,这意味着没有独占定义. (7认同)
  • @Lester 我编辑以清除它。我的 95% 的时间也没有,这个想法是服务可以。在小型应用程序上,它可能有点矫枉过正,但对于任何人来说都是一种很好的做法,并且使用 IoC 容器更容易维护 (2认同)
  • +1 for _Keep in mind MVC 中的“模型”最准确地表示控制器知道的模型,因此是用于视图的模型。_ (2认同)

jga*_*fin 16

在我们开始讨论将所有内容放在哪里之前,您需要了解更多关于MVC的知识.好吧,如果你想遵循这种模式.否则你现在可以停止阅读了.

模式定义非常松散.没有任何内容可以说明控制器,视图或模型应该是什么样子,或者它们应该如何构建.该模式只是说明您应该将各个部分分开,以及它们应该如何相互作用.让我们再看看它们是什么(我的解释).

MVC

模型 模型可以是任何东西.它可以是Web服务,您的存储库,服务类或只是您的域模型.模型是用于获取所需信息的所有内容.将"模型"视为一个层而不仅仅是一个对象.

控制器 控制器是胶水.它从模型中获取信息并使其适应视图,反之亦然.

视图 视图应仅呈现用户看到的内容.

请注意,您不应将模型与视图模型混淆.微软真的应该将"Model"文件夹命名为"ViewModels",因为它们就是这样.我不会直接在视图中使用"模型"中的信息.如果不这样做,则意味着如果更改了视图,则必须更改模型,反之亦然.

答案

该模型不是视图模型,而是图层.模型中的所有内容都用于获取视图所需的信息.控制器获取该信息并将其放入单个视图模型中.

单个控制器操作可能使用对"模型"的一个或多个调用来组合视图所需的信息.

这意味着如果您想获得易于维护和扩展的应用程序,那么您的第二个选项是最正确的.

请注意,可能不需要服务层.您可以直接从控制器调用OR/M. 但是,如果您发现自己重复代码或获取胖控制器,只需将逻辑移动到服务层即可.由于您使用的是正确的视图模型,因此控制器将不会受到该更改的影响.

  • 我希望ASP.NET MVC被命名为ASP.NET ModelView View Controller.这将是一个可怕的名字,但至少它会传达其真正的意义:) (3认同)
  • @jgauffin语义在这里很重要 - 在MVC"模型"中*并不意味着"模型层"; 它**暗示*一个模型对象适合Controller传递给View*.在相当大的应用程序中,MVC架构通常甚至不知道模型/数据层或您选择调用它的任何内容.我编辑的答案试图解释这种混乱......主要是当应用程序很小时,通常不需要额外分离模型和视图模型,因此人们倾向于标记他们的模型并让控制器使用存储库等.全尺寸应用程序,这很少应该发生. (2认同)