MVC 系统是如何工作的?

Posted

技术标签:

【中文标题】MVC 系统是如何工作的?【英文标题】:How does an MVC system work? 【发布时间】:2012-06-02 04:59:09 【问题描述】:

我正在尝试学习 MVC 模式,但每个地方都有不同的说法。所以现在我不知道什么是真正的 MVC。

所以我猜它是最纯粹的 MVC:

模型只是数据并通知数据更改。 View 读取 Model 的消息以更新视图。 ControllerView 读取用户输入并据此更改 Model。

实施

模特不认识任何人。 View 了解 ModelController 了解 ViewModel

伪代码:

/* Model */
class Color 
  color = blue;
  setColor(color);
  notifyUpdate();

/* View */
class ColorPicker(model)
  model.register(update);
  update()
    this.colorToExhibit = model.color;
  

/* Controller */
class Colorize(view, model)
  view.register(update);
  update(color)
    model.setColor(color);
  

一些问题:

    是这样吗? 我不明白为什么 View 不能直接更改 Model,而是通过 Controller。 假设我有动画要在一个动作之后执行。谁必须处理这个动画:模型、视图还是控制器?另外:动画逻辑是模型、视图还是控制器的一部分?更多:假设一个扑克游戏。在用户选择一个动作(例如,“Raise”)后,系统必须播放动画(例如,筹码从玩家位置到桌子)。如何将这个扑克示例(带有动画)视为 MVC?你能解释一下并给出一个伪代码吗?

谢谢。

【问题讨论】:

st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html 我怀疑你在不同的地方找到关于 MVC 的“说点不同的东西”的原因是在实现上存在差异。例如,David 的出色答案听起来是针对 iPhone 开发的——视图“绑定”到模型的概念并不是我从 php Web MVC 系统(如 symfony)中认识的描述性术语。同样,模型不必在理论上的 MVC 系统中引发事件,尽管它们在 Objective C 中会这样做。我认为你最好的选择是拿起一个 MVC 系统并使用它。您是在寻找移动/应用程序开发,还是网络方面的东西?什么语言? @halfer:实际上,我从未做过 iPhone 开发。我的主要经验是 Web 开发,我试图将描述与 ASP.NET MVC 实现分开。我想这种努力取得了一些成功:) 通过“绑定”我并不是指任何特定于语言/框架的东西,而只是有一个骨架视图,它期望模型数据位于特定位置。 “绑定”的行为将填充这些点。框架有不同的工具可以做到这一点,也可以手动完成。 @David,谢谢。实际上,数据由控制器提供给视图 - imo 这不仅需要是模型数据,还可以同样是计算的、随机的、文字的、缓存的数据(等)。我要对 Fabricio 提出的主要观点是,并非控制器逻辑中使用的所有变量都在视图中可用 - 通常程序员会指定要提供的内容,因此两者之间的接口是干净且定义明确的。在我的 (PHP) 经验中,视图无法独立查看模型,除非控制器提供列值、行类或结果集合(等)。 @halfer:所有优点。在这方面,我通常更喜欢区分“模型”和“视图模型”。模型是业务领域对象。在许多情况下,这与 UI 行为是一对一的,但并非总是如此。即使是这样,它仍然是一个不同的问题。 ViewModel 将包含任何特定于视图的数据转换以及要对数据执行的任何特定于视图的函数。在这方面,我喜欢 FubuMVC 方法,即“一个 ViewModel 到 View,一个 ViewModel 回来”。拥有一个瘦 UI 绑定的 ViewModel 对于这些目的非常有用。 【参考方案1】:
模型只是数据并通知数据更改。 View 读取 Model 的消息以更新视图。 控制器从 View 中读取用户输入并据此更改模型。

模型不仅仅是数据。模型也是业务逻辑。它包含系统的所有智能,或者至少是幕后智能的抽象(例如数据库调用或其他服务调用)。想想这句话,“让你的模型重而你的控制器轻。”

模型不认识任何人。 视图知道模型。 控制器知道视图和模型。

模型没有人知道它是正确的。模型应该在应用程序之间是可移植的,并且不应该以任何方式依赖于 UI 问题。 (在这种情况下,视图和控制器是 UI 问题。)

视图知道模型,也是正确的。视图基本上“绑定”到模型。它呈现所有 UI 元素,并将模型数据相应地放置在 UI 元素中。

控制器某种“了解视图”。它知道它应该直接控制哪个视图,但它对那个视图一无所知关于。它也不知道先前来自哪个控件的哪个视图。控制器响应事件。来自 UI 的事件,带有某种状态信息(可能是 ViewModel),通过模型(业务逻辑发生的地方)引导逻辑控制,并以模型(或 ViewModel,如果形状特定视图的特定数据与模型不同)和视图。

我不明白为什么 View 不能直接更改 Model,而是通过 Controller。

视图可以在用户交互的上下文中操作模型,但不应期望这些更改以任何方式持续存在。视图应该被认为是“客户端”并且不知道任何“服务器端”。 (即使您说的是本机应用程序而不是 Web 应用程序。)持久化任何更改都被视为 UI“动作”或“事件”,并将转到 Controller 以使其发生。

假设我有一个动作后要执行的动画。谁必须处理这个动画:模型、视图还是控制器?另外:动画逻辑是模型、视图或控制器的一部分?

动画听起来像是完全基于 UI 的操作。它将在视图内。除了 UI 动画,还有更多的事情发生吗?动画是否在后端改变任何东西?例如,如果我有一个 Web 应用程序,并且当页面加载时,我想淡入一些数据(动画)......这完全在视图中。数据将像任何其他数据一样传递到视图,并且动画完全在 UI(视图)内进行。从模型或控制器的角度来看,它不会任何事情。

假设一个扑克游戏。在用户选择一个动作(例如,“Raise”)后,系统必须播放动画(例如,筹码从玩家位置到桌子)。如何将这个扑克示例(带有动画)视为 MVC?你能解释一下并给出一个伪代码吗?

动作(“Raise”)是一个控制器事件。 UI 将联系控制器以执行“提升”。所以Controller可能有这样的方法:

View Raise(GameState state)

    // Interact with the Models to update the known state of the game.
    // The Models would perform the actual Poker game logic.
    // Respond with a View bound to updated Models.

一旦控制器使用新视图响应 UI,该视图将包含要显示给用户的任何动画。 (毕竟,除非动作成功,否则您不希望执行动画,对吗?当 Controller 以指示成功动作的新 View 响应 UI 时,动画就会播放。它可能会改为响应 UI带有指示错误的视图,在这种情况下,视图会显示其他内容。)

【讨论】:

我对控制器“有点”了解视图感到有点困惑。 “它应该直接控制哪个视图”是什么意思?你能详细说明一下吗? @BT:控制器有点像协调员/调度员。它接收请求或某种输入,与模型交互以根据该输入更改系统状态,并将输出定向到视图。因此,它“有点”了解视图,因为它需要知道将哪个视图作为输出。相反,被渲染为输出的视图对刚刚渲染它的控制器一无所知。从控制器到视图的流程是单向的。 好的,所以当您谈论视图时,您指的是显示或隐藏的整个屏幕/页面,对吗?这个概念可以推广到复合视图吗? @BT:最终,视图是呈现给用户的 UI 演示。它是否由多个组件组成,是否具有显示/隐藏组件等,都取决于您决定如何构建视图。不同的技术/框架/等。将以不同的方式处理这些概念。但最终的结果是为用户提供某种交互界面。从概念上讲,这就是视图,在物理上,该视图可能由许多不同的元素组成,其中任何一个或多个元素在其各自的技术中都可以称为“视图”。【参考方案2】:

我将使用简单的银行类比。

出纳员是意见。 跑步者是控制器。 银行家是榜样。

银行家是聪明人,他们了解所有业务逻辑并进行所有复杂的计算。

Runners 用于将钱(数据)从 Bankers 传输到 Tellers。

柜员把钱交给顾客。

一个简单的表示:

型号

public class BankAccount

     public int ID;
     public int Balance;

     public BankAccount(int id)
     
         ID = id;
         Balance = DetermineAmount();
     

     public int DetermineAmount()
     
         // Gather transaction info, debits, credits and return a
         // sum of the amount left in the account depending on the
         // id provided.
     


控制器

    public class BankAccountController
    

         public ViewResult Index(int id)
         
             BankAccount account = new BankAccount(id);
             return View(account);
         

    

查看

<ul id="account-info">
   <li>Account ID: `@Model.ID`</li>    
   <li>Balance: `@Model.Balance`</li>
</ul>

【讨论】:

对我来说也一样,这个非常简单的例子完美地补充了公认的答案。【参考方案3】:

如果您对历史上的true MVC 感兴趣,请从Trygve Reenskaug 开始。他在 1970 年代后期创建(观察到?,编目??)它。首先,请阅读 1979 年的 "Models-Views-Controllers"。它定义了术语。请注意它的标题 - 所有三个角色都是多元化的。这是大多数人似乎会弄错的第一件事。

我发现的关于 MVC 最初用途的最佳描述实际上是在 2004 年题为 "Inside Smalltalk MVC" 的演示文稿中。我猜想描述 Smalltalk 80 最终版 MVC 的规范论文是 Krasner 和 Pope 的 "A Cookbook for Using the Model-View-Controller User Interface Paradigm in the Smalltalk-80" 和 史蒂夫伯贝克的"Applications Programming in Smalltalk-80: How to use Model-View-Controller (MVC)"。这两篇论文都值得一读。

如果您有时间消磨时间并且不介意听 Robert Martin 的演讲,那么他在 keynote at Ruby Midwest 2011 上的表现很好,触及了 MVC。这是一个多小时,但非常有趣和有启发性。我倾向于遵循他的观点,即大多数实现都会导致 MVC 错误。我花了一点时间环顾四周,最后找到了一个可以链接到描述 MVC 的图表。我喜欢的是Pope and Krasner

(来源:as3dp.com)

在我看来,以下是重点:

模型实例负责将更改通知感兴趣的对象。请注意,这些可以是 任何 对象实例。该图显示了在此处接收更新的视图和控制器。 视图负责查询当前状态并显示结果。它们通常也会执行过滤或数据转换。 控制器负责接受用户输入并将视图消息转发到视图。 查看消息是 MVC 中的一个常见主题。重要的是这些独立于 UI 世界——这些不是鼠标点击,而是一种特定于视图的事件语言。这就引出了下一点。 视图不依赖于控制器。控制器负责安排和创建视图,并提供世界其他部分与视图之间的接口。 在完美世界中,视图负责使模型表示可见。这就是将 MVC 应用于桌面应用程序时的工作原理。

现实情况是,MVC 已针对网络世界进行了扭曲和重写。它不再是真正的 MVC,或者可能只是重新定义了 MVC。这就是为什么你会看到这么多不同的 MVC 观点和表示。如果你正在研究编写桌面风格的应用程序,那么看看 Krasner & Pope 的东西。如果您正在研究如何将 MVC 应用于 Web,那么我推荐 Bob 叔叔的主题演讲,以寻找更适合 Web 应用程序的替代方案 - 他称之为 Interactor、Entity、Boundary Architecture,因为它缺乏一个更好的名字。挖掘与他关于“失落的建筑年代”的演讲相关的内容

【讨论】:

以上是关于MVC 系统是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

MVC(ASP.NET MVC)带3层架构如何协同工作?

Spring MVC 中的不同上下文是如何工作的?

如何获得当前用户,以及如何使用User类的MVC5

写出MVC的工作原理

我是 .NET Core 2.1 MVC 的新手,我无法理解一些事情是如何工作的

如何在 ASP MVC 中实现工作单元、存储库和业务逻辑?