一个模型、视图和控制器分别应该包含什么?

10

我一直在学习模型-视图-控制器范例("MVC"),但有些教程之间存在矛盾,让我感到很困惑。

目前我对这个过程的理解是:

路由器/调度器/前置控制器:

  • 虽然在 "MVC" 的名称中没有特别提到,但路由器仍然是非常重要的一个部分。它将请求从原始 URL 转换为具体的控制器。例如,将一个请求路由到应用程序的“问题控制器”,URL 为 www.StackUnderflow.com/question/123。

模型:

  • 这里收集了来自某些存储源(如数据库或 XML 文件)的原始数据。模型作为抽象层,将 控制器 对特定数据的请求转换为(例如)SQL 查询,并将查询结果转换为标准格式,如数据对象。

  • 例如,在上述 /browse/all 情况下:

    • “问题控制器”将询问模型:“请提供问题 123 的数据。”
    • 模型然后将其转换为 "SELECT * FROM Questions WHERE Id = 123;" 并将其发送到数据库。
    • 数据库将返回一个“问题”记录给模型。
    • 模型将接受记录,并将其转换为问题数据对象
    • 然后,模型执行同样的操作 "SELECT * FROM Answers WHERE QuestionID = 123;" 并从结果集创建答案对象数组,并将其添加到问题对象的 answers 成员变量中。
    • 然后,模型将问题对象返回给“问题控制器”

控制器:

  • 这是应用程序的工作核心。除了在 模型视图 之间传递消息外,控制器 还负责诸如授权 和应用程序/"业务"逻辑 编辑:根据答案,业务逻辑属于模型。

  • 在持续的示例中,控制器负责以下事项:

    • 确保用户已登录。
    • 从 URL 中确定问题 ID。
    • 确定要使用哪个视图。
    • 发送 HTTP 状态码并在需要时进行重定向。
    • 模型 请求数据,并将所需数据存储在成员变量中。

视图:

  • 总体而言,视图是应用程序中最简单的部分。在基本应用程序中,它主要由 HTML 模板组成。这些模板将包含来自控制器成员变量的数据插入到模板中的占位符中:

例如:

<html>

  <head>
    <title>
      <?php $question->getTitle() ?>
    </title>
  </head>

  <body>
    <h1> <?php $question->getQuestionText(); ?> </h1>
    <h2> Answers: </h2>
    <div class="answerList"> 
      <?php formatAnswerList($question->getAnswers()); ?> 
    </div>
  </body>

</html>
  • View 还包含了格式化数据以向用户传递的方法。比如,上面的 formatAnswerList() 方法会获取来自 Controller 的答案数组,并循环调用像是 include $markupPath . "/formatAnswer.inc" 这样的代码片段,用于生成答案容器的小模板。
2个回答

2

@David:更重要的是,控制器中是否有我使用的示例不应该在那里?我认为所有内容都限于描述状态(而且据我理解,QuestionC也负责记住状态)或将信息传递给/从视图或模型中传递。HTTP代码部分(或实际上任何与HTML相关的内容,例如元标记、关键字或页面标题)应该是视图的一部分,还是在控制器中可以?所使用的示例非常面向CRUD,我不想在以后混淆:所以您的意思是所有繁重的工作都是模型吗? - AgentConundrum
@David:太好了。我觉得我真的开始理解了。请接受这个“已接受答案”的奖金作为我的感激之情的象征。 :) - AgentConundrum
@AgentConundrum: 哎呀,我其实希望得到一个零分采纳答案。我离成为无名英雄徽章还有一步之遥。不过我不知道事后取消投票是否会产生同样的效果,所以还是保留投票吧 :) - David
@David:我刚试图撤销投票,但由于我投票已经两个小时了,所以投票已被锁定。如果你编辑答案(一些微不足道的东西),我会撤回投票并看看是否有帮助。如果没有,我会取消接受答案,并查看在0票的情况下再次接受它是否会给你徽章。能够给某人金徽章是很好的,但我认为“零票接受”的“无名英雄”并不像我们想象的那么简单——看看一些拥有这种徽章的人,你就会明白我的意思。此外,它说“零分接受答案:超过10个和总数的25%。”不知道最后一部分是什么意思... - AgentConundrum
@AgentConundrum:我很感激,但不用担心。据我所知,我只需要在达到44个被接受的答案(25%)之前获得11个零分被接受的答案(超过10个)。我还需要4个。这很容易,注意我获得顽强徽章的情况,在我获得30个总数(20%)之前,我有6个零分。 - David
显示剩余4条评论

0

基本上你已经把所有东西都放在了正确的位置。

在你的例子中,你定义了一个Question类 - 这将被称为ViewModel,简单地说就是用于容纳在View中使用/从View检索的所有数据的容器。

在某些情况下,我看到ViewModel被忽略了,而Model被传递到View中 - 当我第一次查看教程时,这让我感到困惑,我不喜欢省略ViewModel,我认为这会使事情变得混乱。


你的ViewModel是我的Controller吗?还是我搞混了?我认为这个模式包含三个不同的对象(因此我的View引用了$question而不是$self)。根据你所说的忽略ViewModel,那是否意味着没有Controller,只有Model和View直接交流? - AgentConundrum
将模型视为实际对象和逻辑的域,将ViewModel视为向视图提供数据的简单POCO DTO,而将控制器作为传递信息的中继操作员(并处理任何与UI相关的事物,如不属于模型的会话状态)。 - David
@David:好的,所以“ViewModel”只是你用来保存数据传输/存储的对象,Model 用于处理数据,Controller 用于存储数据/状态并在 Model <-> View 之间传递数据,而 View 只是用于呈现 HTML?这基本上是正确的吗? - AgentConundrum
@AgentConundrum: 听起来大概就是这样。模型可以变得相当复杂。对于我的大多数网站,业务逻辑都保留在服务层后面,而模型本质上只是与服务进行交互。在这种情况下,它最终变得比我想象的更加过程化,但它就是这样。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接