【问题标题】:Understanding MVC: Whats the concept of "Fat" on models, "Skinny" on controllers?理解 MVC:模型上的“胖”、控制器上的“瘦”是什么概念?
【发布时间】:2011-03-07 18:52:34
【问题描述】:

我试图理解模型上的“胖”与控制器上的“瘦”的概念,根据我一直在讨论的内容,我有以下示例(摘自 freenode 讨论):

Q:关于 MVC 范式,它说 Fat 模型,skinny 控制器。我在这里想,如果我有很多方法(在控制器上)只使用一些抽象方法来 CRUD(在模型上),我是在创建一个胖控制器而不是一个模型吗?或者他们说,胖模型,参考返回的内容而不是输入的内容?那是我从未理解过的东西 =) 任何 cmets 都会受到赞赏!非常感谢

OBS1:我不是在做模型的什么,在控制器中,我只是有控制模型的方法

OBS2:假设“checkIfEmailExists()”有“john@hotmail.com”作为参数。该方法将从查询该参数是否存在于表中的模型方法中获取返回值,返回布尔值。如果为0,“checkIFemailExists()”将调用不同的模型方法,这个,他只是另一个抽象方法,执行更新操作。

OBS3:“checkIfEmailExists()”不只是一个控制器吗?他实际上并没有执行任何 CRUD,他只是在比较值等。这让我感到困惑,因为在我的脑海中这是一个控制器:S

注意:我想这不是最好的例子,因为说“检查是否存在”,听起来像是查询我的表操作

Q2:再问一个问题,假设我有一个视图表单,该电子邮件地址参数是从哪里发送的。你是说视图直接进入模型?

Q3:控制器不应该在他们之间行动吗?这就是范式

最后说明:讨论结束,说我错了,希望没问题(我正在学习)。但是,Q2 和 Q3 的正确答案是什么?

感谢您的关注

【问题讨论】:

  • 只是一个观察:如果您提出简短、条理清晰、中肯的问题,而不是把想到的所有事情都写在主题。

标签: php model-view-controller paradigms


【解决方案1】:

我使用 MVC 范式已经很长时间了,我可以与您分享我的经验。

“模型”部分负责处理并非严格意义上的“Web”的所有内容,例如验证、逻辑、数据访问等。将其视为一种混合业务层 + 数据访问层。您还可以在单​​独的程序集中使用 BLL+DAL,并使用 MVC 的“模型”部分作为 BLL 和应用程序之间的桥梁,并添加特定于 MVC 应用程序且与 BLL 无关的类,例如 ViewData 类等。

“控制器”部分负责处理特定于 Web 的内容,例如身份验证、cookie、GET 和 POST、查询字符串等。它使用模型和/或 BLL 中存在的内容并发送具有将视图呈现给用户。

“视图”是您的 html 模板,可以从控制器接收数据并显示它。视图中不应该进行任何逻辑操作,所以没有“if”语句,没有循环等。 如果您发现自己有这样的需求,那么您需要一些“帮助”方法来创建所需的 html,然后从视图中调用它们。 因此视图只接收数据,并向用户提供链接/表单以将数据发布到控制器,但它们不详细说明任何内容。

希望这能消除您的一些疑虑。

【讨论】:

  • 说得好,但是我不同意观点,它们不应该缺少所有逻辑,需要显示逻辑。通常,为了从视图中删除所有逻辑,人们最终会创建太多的局部视图,或者更糟糕的是,他们将“视图”数据(例如 HTML 或 XML)添加到控制器或辅助方法中。更好的查看方式是您应该只将形成的数据传递给视图,除了显示它之外,不需要对其进行进一步的操作,如果显示数据需要循环,那就这样吧。
  • @evolve 我同意,将 放在视图中以显示单个单词并没有太大问题需要。至少如果它在视图中,则语言已与控制器分离。
  • Matteo,不是说“将 [模型] 视为一种混合的业务层 + 数据访问层”违反了单一职责原则吗?我想知道“胖模型”一词是否是反模式。
【解决方案2】:

我一直认为这意味着模型应该以更加面向对象的方式封装与这些模型相关的逻辑,而不是以更加程序化的方式在控制器中包含所有逻辑。引用The Cathedral and the Bazaar:

智能数据结构和愚蠢的代码比其他方式工作得更好。

【讨论】:

    【解决方案3】:

    我认为可以通过让控制器执行不涉及/很少涉及业务逻辑的“语法”相关操作并使用模型执行“语义”相关操作来实现良好的控制器/模型分离。

    这种分离的一个很好的例子是:

    您可以在控制器中对电子邮件执行正则表达式检查,但您不会在控制器中对该电子邮件执行 ldap 匹配。

    【讨论】:

      【解决方案4】:

      我可能表现出我的偏见(对 C#),但我认为除非您使用面向对象的编程风格,否则谈论 MVC 没有多大意义。控制器不是方法,它是分组到一个类中的方法的集合,每个方法都处理一些输入(url/request)。模型不是访问数据库的一种方式(即数据访问层),它是一组属性和方法的集合,这些属性和方法封装了应用程序中的一些可识别实体:人、预订、产品等。想想看,控制器处理输入,模型包含数据——当然,这是简化的。

      对我来说,“胖”与“瘦”的问题是您的业务逻辑在哪里存在的问题。如果您的控制器中有很多与控制器相关的逻辑,而不是简单地处理输入,而是实现业务逻辑,那么您的控制器比您简单地使用它们来将请求转换为模型组合并传递给视图进行渲染的情况相对更胖.以我的经验,这并不总是一个非此即彼的决定。很多时候,模型中有业务逻辑(验证、关系维护、审计),而控制器中有应用程序逻辑(权限验证、清理等)。

      【讨论】:

      • MVC 不一定绑定到面向对象的编程。您还可以用 C 或任何其他非 OOP 语言实现分离数据、逻辑和表示的想法。当然,它在 OOP 中效果最好 :)
      • @Techpriester - 但是,尽管语言支持(或缺乏),但您不是在应用面向对象的原则吗?您可能最终会得到 3 个大对象,但您仍然需要以这种方式思考它们才能理解它。
      • 并非如此。在非 OOP 语言中使用 MVC 原则时,您只需在三个部分之间进行清晰的分离。抽象和封装的概念可以(并且应该)应用于任何语言,即使没有 OO 特性。
      【解决方案5】:

      您的应用程序是 M。它应该能够独立于 V 和 C。V 和 C 形成您应用程序的用户界面。无论是 Web 界面还是命令行界面,对于运行应用程序的核心业务逻辑都无关紧要。您希望模型具有业务逻辑。

      如果你有一个胖控制器,例如充满了业务逻辑,你没有坚持 MVC 的宗旨。控制器的唯一职责是处理 UI 请求并将其委托给模型。这就是为什么它应该是瘦的。它应该只包含它所负责的代码。

      简化示例

      public function fooAction()
      {
          if(isset($_POST['bar'])) {
              $bar = Sanitizer::sanitize($_POST['bar']);
              $rows = $this->database->query('SELECT * from table');
              try {
                  foreach($rows as $row) {
                      $row->foo = $bar;
                      $row->save();
                  }
              } catch (Exception $e) {
                  $this->render('errorPage');
                  exit;
              }
              $this->render('successPage');
          } else {
              $this->render('fooPage');
          }
      }
      

      应该是什么时候

      public function fooAction()
      {
          if(isset($_POST['bar'])) {
              $success = $this->tableGateway->updateFoo($_GET['bar']);
              $page    = $success ? 'successPage' : 'errorPage';
              $this->render($page);
          } else {
              $this->render('fooPage');
          }
      }
      

      因为这就是控制器需要知道的全部内容。它不应该更新行。它应该只是告诉模型有人要求进行此更改。更新是管理行的类的责任。此外,控制器不一定要清理值。

      至于Q2和Q3,请看我对Can I call a Model from the View的回复。

      【讨论】:

      • 说得好!将您的业务逻辑置于控制器之外。
      • +1 第二段是黄金。瘦控制器是遵守 MVC 架构和单一职责原则的体现。
      • 所以如果我做对了,我所有的模型都将拥有所有的 crud 功能,而我的所有控制器都将拥有“逻辑”(例如表单验证、用户重定向等)?我说的对吗?
      • @Lykos 差不多。您的模型不仅仅是数据库。这是您的整个应用程序减去用户界面。您的模型将包含数据访问处理逻辑。表单验证是 UI 的一个方面,但不应直接进入控制器,而应进入专用的验证类(因此您可以重用它们)。不过,您可以在控制器中使用它们。重定向不是 UI 而是传输层,例如当您使用 HTTP 时,它会适合某种类型的 Response 对象。控制器实际上只是一个委托人。
      • 好吧,就我而言,我最近开始学习 CodeIgniter,所以这里有一个例子。假设我有一个进行注册的用户。所有的杂物 - 插入 - 都将在我的 user_model 中。为了对帖子输入应用一些验证,我必须加载 form_validation 类。因此,我之前所说的问题的重点就在这里。我应该将我的验证(form_validation_run() 函数)应用到我的控制器还是将其推送到我的 user_model 中?我应该在哪里加载 form_validation 类?在我的模型中还是在控制器中??
      猜你喜欢
      • 1970-01-01
      • 2010-10-02
      • 2012-01-25
      • 1970-01-01
      • 2015-04-24
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      相关资源
      最近更新 更多