104

我一直在阅读很多提倡胖模型和瘦控制器方法的博客,尤其是。Rails 营地。结果,路由器基本上只是弄清楚在什么控制器上调用什么方法,而所有控制器方法所做的就是调用模型上的相应方法,然后调出视图。所以我在这里有两个我不明白的问题:

  1. 控制器和路由器实际上并没有做太多不同的任务,只是在基于路由的上帝模型上调用一个方法。
  2. 模特做的太多了。发送电子邮件、创建关系、删除和修改其他模型、排队任务等。基本上,现在您拥有神一样的对象,它们应该完成所有可能与建模和处理数据有关的事情。

你在哪里画线?这不就是掉入神模式了吗?

4

3 回答 3

165

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

一些理论

给出这种建议的人似乎受到了一个非常普遍的误解的困扰。因此,让我首先澄清一下:在现代 MVC 设计模式中,模型不是类或对象。模型是一层。

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

模型层由以下主要部分组成:

  • 领域对象

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

  • 存储抽象:

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

  • 服务:

    负责应用程序逻辑的结构(即域对象之间的交互以及域对象与存储抽象之间的交互)。它们应该充当表示层与模型层交互的“接口”。这通常是在类 Rails 代码中最终出现在控制器中的内容。

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

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

那么神器呢?

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

此类更改可能会立即引起一些反应,或仅影响视图实例从模型层请求的数据,或两者兼而有之。

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

结束语

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

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

对于使用 PHP 作为主要语言的人,这篇文章可能是相关的。这是对模型层的更长描述,带有一些代码片段。

于 2012-12-26T19:53:50.653 回答
5

如果“模型”类的实现很差,是的,您的担忧是相关的。模型类不应该做电子邮件(基础设施任务)。

真正的问题是 MVC 中的模型意味着什么。它不限于具有几种方法的 POCO 类。MVC 中的模型意味着数据和业务逻辑。将其视为经典核心 POCO 模型的超集。

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

投入基础设施程序集和数据访问层并使用注入将其传递给 BPL,然后您的流程将按预期使用 MVC。

BPL 可以调用 UoW / Respository 模式,并通过注入的对象或接口模式执行业务规则和调用基础设施功能。

所以建议保持控制器瘦身并不意味着经典Core模型中的“人”类应该有50个方法,并且直接调用Email。你认为这是错误的是对的。

如果直接调用,控制器可能仍需要实例化基础设施类并将其注入 BPL 或核心层。应该有一个业务层或至少有一个类来编排跨经典对象模型类的调用。好吧,这就是我的“观点”;-)

对于 MVC 的通用性,wiki 描述http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

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

于 2012-12-26T19:08:24.107 回答
-1

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

于 2012-12-26T18:54:30.170 回答