MVC(模型-视图-控制器)图解——输入、更新、渲染

MVC 模式的工作原理,在一张交互式画布上讲清楚:用户输入如何到达控制器、更新模型,模型再通知视图重新渲染。

MVC 用一条规则把应用分成三部分:控制器处理输入,模型拥有状态与规则,视图渲染模型——而视图和控制器都不直接碰状态。

MVC(模型-视图-控制器)图解——输入、更新、渲染

The interactive FlowJam canvas for this explanation — every lane, row and arrow above is a real QueryChart diagram you can open and edit.

How to read this visual

  • 按箭头画出的顺序走这个循环:用户到控制器,到模型,到视图,再回到用户。
  • 三列就是三幕:输入到达,状态更新,输出渲染。
  • 泳道就是关注点分离——每条泳道负责一类工作,谁也不干别人的活。

输入

“用户与界面交互”启动这个循环,而“控制器接收输入”是那个指挥交通的角色:它读取动作,判断它意味着什么,再指示模型。控制器上的注释把规则说明白了——它自己不持有任何状态,所以它可以处理大量请求而什么都不用记住。

更新

“控制器更新模型”跨进模型的泳道,而“模型持有状态与业务规则”就是模型的定义:它是数据以及管住这些数据的那些规则的唯一可信来源。“模型把变更通知给观察者”是通知那一半——模型并不告诉视图该画什么,它只宣布有东西变了,任意数量的视图都可以监听。

渲染

“视图根据模型重新渲染”是视图唯一的工作:读模型,把它显示出来。它的注释指出了那条防止 MVC 塌掉的纪律——视图从不改动数据,它只询问和显示。“用户看到更新后的界面”在用户那一行合上了这个圆,而每一次交互也正是从这里开始、在这里结束。

Key relationships and takeaways

  • 控制器处理输入;模型拥有状态;视图负责渲染——三种职责,三条泳道。
  • 视图和控制器都不写数据;所有变更都流经模型。
  • 模型是通知观察者,而不是命令视图,所以一个模型可以驱动多个视图。
  • 这种分离让每一部分都能单独测试——这正是这个模式最初带来的回报。
  • MVC 是许多现代模式的祖先(MVVM、MVP、Redux 式的状态库),它们保留的都是同一套分离。

When to use this visual

  • 在开发者去读某个框架的文档之前,先把这个模式讲给他听——这个三角就是每个框架都在实现的那张地图。
  • 解释一个代码库为什么难改:状态被放在视图里处理,这违反 MVC,而且在画布上一眼就能看见。
  • 把 MVC 与整洁架构那张图解里的分层架构做对比。

运作方式

  1. 把你的框架映射到这个三角上

    用你框架里真实的部件重命名这三个方框——路由文件当控制器、ORM 模型当模型、模板当视图——让这个模式变得具体。

  2. 加上路由这一步

    如果你的框架有路由,就在用户和控制器之间插一个路由步骤,并连到它分发到的那个控制器。

  3. 画出多个视图

    再加一个视图方框,让两个视图同时监听同一个模型——一个列表视图和一个详情视图——来演示这个模式所依赖的观察者关系。

  4. 补上持久化层

    在模型后面扩出一个数据库步骤,并注明它归模型所有,控制器和视图从不直接碰它。

常见问题

什么是 MVC?

MVC——模型、视图、控制器——是一种把应用分成三部分的软件模式:控制器处理输入,模型拥有数据和业务规则,视图渲染模型。这种分离的好处是每一部分都可以独立开发和测试,同一个模型也可以被多个视图展示。大多数 Web 框架都建立在这个模式之上。

为什么模型是 MVC 的中心?

因为模型是唯一可信来源。如果控制器和视图都能写数据,它们就会各自漂移、为状态打架。把所有变更都放在模型里,意味着数据规则只存在于一个地方,而视图永远只是一个一致模型的投影。图上把模型的两个方框放进它自己的泳道,正是因为这个原因。

如果我把逻辑写进视图会怎样?

你会得到一种有时被称为“胖视图”的反模式:显示代码和业务规则混在一起,不渲染就没法测试,还会和模型渐行渐远。同样的批评也适用于一个持有业务逻辑、而不是把它委派出去的控制器。MVC 的纪律就是各条泳道各守其位——图上那三行分开的方框,就是这条规则被画了出来。

MVC 和现代框架是什么关系?

大多数现代框架都用新名字保留了这个三角:MVVM 加了一层视图模型,MVP 给视图配了一个展示器,而 Redux 这类状态管理库本质上就是加了更严格通知规则的模型。画布上的核心循环——输入改变状态,状态驱动输出——是它们每一个都保住的不变量。

在 QueryChart(FlowJam)中编辑这张图解

把上面这张 MVC 画布原样打开成你自己的图表,把方框改成你框架里的名字,追一遍你自己的请求路径。

在 QueryChart(FlowJam)中编辑这张图解

可视化图解中的更多内容