胖模型和瘦控制器听起来像是在创建上帝模型。


91

我读过很多博客,这些博客提倡胖模型和瘦控制器方法,尤其是。Rails阵营。结果,路由器基本上只是想找出要在哪个控制器上调用的方法,而所有控制器方法都需要在模型上调用相应的方法,然后调出视图。所以我在这里有两个我不明白的问题:

  1. 除了仅基于路由在类似于上帝的模型上调用方法外,控制器和路由器实际上并没有执行很多不同的任务。
  2. 模型做得太多了。发送电子邮件,创建关系,删除和修改其他模型,排队任务等。基本上,现在您有了像神一样的对象,它们应该执行与建模和数据处理有关或不涉及的一切事情。

您在哪里划界线?这不只是落入上帝的榜样吗?

Answers:


136

将Rails作为MVC设计模式的主要内容可能不是最好的主意。所述框架存在一些固有的缺陷(我在一篇文章中对此进行了详细阐述),而社区才刚刚开始解决这一问题。您可以将DataMapper2 开发视为第一步。

一些理论

提出建议的人们似乎受到一种非常普遍的误解的困扰。因此,让我从清除它开始:在现代MVC设计模式中,模型不是类或对象。模型是一层。

MVC模式背后的核心思想是关注分离,其中的第一步是表示层和模型层之间的划分。就像表示层分为控制器(实例,负责处理用户输入),视图(实例,负责UI逻辑)和模板/布局一样,模型层也是如此。

模型层组成的主要部分包括:

  • 域对象

    也称为域实体,业务对象或模型对象(我不喜欢后者的名称,因为它只会增加混乱)。人们通常错误地将这些结构称为“模型”。它们负责包含业务规则(域逻辑的特定单元的所有数学和验证)。

  • 存储抽象:

    通常使用数据映射器模式来实现(不要与已滥用此名称的ORM混淆)。这些实例通常负责从域对象存储和检索信息。每个域对象可以具有多个映射器,就像有几种存储形式(DB,缓存,会话,Cookie,/ dev / null)一样。

  • 服务:

    负责应用程序逻辑的结构(即,域对象之间的交互以及域对象与存储抽象之间的交互)。它们应该像表示层通过其与模型层进行交互的“界面”一样起作用。这通常是在类似Rails的代码中最终出现在控制器中的结果。

这些组之间的空间中可能还存在一些结构:DAO工作单元存储库

哦……当我们(在网络环境中)谈论与MVC应用程序交互的用户时,它不是人类。“用户”实际上是您的Web浏览器。

那神灵呢?

控制器应该与服务交互,而不是使用一些令人恐惧的整体模型。您将数据从用户输入传递到特定服务(例如MailServiceRecognitionService)。通过这种方式,控制器可以更改模型层的状态,但这是通过使用清晰的API来完成的,并且不会弄乱内部结构(这会导致泄漏的抽象)。

这样的更改可能会引起一些立即反应,或者仅影响视图实例从模型层请求的数据,或者两者都影响。

每个服务可以与任何数量(尽管通常只有少数)域对象和存储抽象进行交互。例如,他们RecogitionService可能不太在乎文章的存储抽象。

结束语

通过这种方式,您可以获得可以在任何级别进行单元测试,耦合度低(如果正确实现)并且架构易于理解的应用程序。

但是,请记住:MVC不适用于小型应用程序。如果您使用MVC模式编写留言簿页面,那么您做错了。此模式用于在大规模应用程序中执行法律和秩序

对于使用PHP作为主要语言的人们,这篇文章可能是相关的。通过一些代码片段,对模型层进行了较长的描述。


非常有用且完整的答案!您知道哪本书对MVC架构模式有更多的解释吗?尤其是在模型部分,每个人都错误地认为“模型代表数据,什么也不做。” 听起来更像是领域对象的概念,而不是'模型'-> tomdalling.com/blog/software-design/…– thermz 2013
6

1
@thermz,afaik,确实没有专门涉及MVC模式的书籍。我通常只是告诉人们阅读PoEAA,然后再进行挖掘。也许此链接列表可能有用。我发现,当人们对OOP原理和概念有了扎实的了解时,这种模式就变得很容易理解。
tereško

@tereško漂亮的答案。Hibernate是否可以做到这一点?我不相信这里的答案- > stackoverflow.com/questions/1308096/...
俺看-Zerob

您可能会注意到@ Ankan-Zerob,我不是Java开发人员,但是据我对Hibernate的了解,它为持久层提供了完整的工具集。它将为您提供此处描述的部分内容,但不会提供完整的模型层。
tereško

3
据我所知,@ johnny。php的大多数所谓的“ mvc框架”都是Rails的变体。并且,作为课程的一部分,其中大多数都带有一些基于活动记录的ORM解决方案(众所周知,这些事情对于DB更改非常脆弱)。您可以使用SF2.x或ZF2.x实现类似的事情,但是框架的重点不是实现/强制执行特定的架构,而是提供工具。同样,对于MVC,它是由应用程序代码而不是框架来实现的。
tereško

5

如果“模型”类的实现不佳,是的,则您的关注是相关的。模型类不应执行电子邮件(基础结构任务)。

真正的问题是MVC中的模型暗示了什么。它不限于使用几种方法的POCO类。MVC中的模型表示数据和业务逻辑。将其视为经典核心POCO模型的超集。

视图====控制器====模型--->业务流程层->核心模型

放入基础结构程序集和数据访问层,并使用注入将其交付给BPL,然后您的流程将按预期使用MVC。

BPL可以调用UoW /存储库模式,并通过注入的对象或接口模式来执行业务规则并调用基础结构功能。

因此,建议使控制器保持瘦状态并不意味着经典Core模型中的“ person”类应具有50种方法,并直接调用Email。您认为这是错误的是对的。

如果直接调用,可能仍然需要Controller实例化基础结构类并将其注入BPL或核心层。应该有一个业务层,或者至少应有一些类来协调经典对象模型类之间的调用。好吧,那还是我的“观点” ;-)

对于MVC的一般用法,请参见Wiki描述http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

一个讨论MVC中“ M”的小博客。http://www.thedeveloperday.com/skinny-controllers/


1
如果您不同意至少有礼貌地证明自己的观点
phil soady 2012年

-1

我认为您可以区分单个胖模型(可能命名为App或Application)和几个分为逻辑组(业务,客户,订单,消息)的胖模型。后者是我构建应用程序的方式,每个模型大致对应于关系数据库中的数据库表或文档数据库中的集合。这些模型处理创建,更新和操作构成模型的数据的所有方面,无论是与数据库对话还是调用API。控制器非常薄,几乎不需要调用适当的模型并选择模板。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.