本节致力于让你理解 MVC 的概念,为后面的学习打下基础。

MVC 的定义

MVC 是 Model-View-Controller 的缩写。Model(模型) - View(视图) - Controller(控制器)是一个用于实现图形用户界面(GUI)程序的软件架构模式。

MVC 用于 GUI 开发

学习 MVC 前一定要意识到它是用于 GUI 开发的。

MVC 是一种模式

当我们讨论软件开发时,模式指常规角色的组合。在一种模式中,每个角色都有自己的职责并与其他角色进行交互。

软件旨在处理数据。通过长时间的观察,人们发现 GUI 程序的数据处理周期分以下三个步骤:

  • 程序通过用户界面向用户显示数据

  • 用户通过操作用户界面来更改数据并表达意图

  • 程序(通过逻辑)处理数据并响应用户

上面的流程涉及到了几个角色?
答案是三个,数据、用户界面和逻辑。

注:因为用户不属于程序的一部分,所以设计程序时不将它作为角色。

角色 职责
Data 携带显示给用户的信息或从用户收集的信息
User Interface 显式数据,收集数据,将操作传递给逻辑
Logic 处理数据,响应用户操作,选择适当的用户界面来显示数据

随着演进,这三个角色都有了更恰当的名称,Model、View 和 Controller。

下面列出 MVC 各角色间如何交互和各自的一些规则,在你编写自己的 MVC 程序时尽量不要打破这些规则。如果你无意间打破这些规则,你的 MVC 很可能就转变成了 MVC 的某种变体,这将在下面讨论。

  • Controller:

    • 响应用户命令

    • 操作 Model

    • 为 Model 选择适当的 View,或是为 View 选择合适的 Model

    • 请求 View 去渲染显式 Model

  • View:

    • 将用户的命令或操作传递给 Controller

    • View 不一定知道它的 Model 类型

    • 在 Controller 分配具体实例前,View 不知道它的 Model 类的实例(实际的视图模型)

    • View 知道如何在 Controller 请求时渲染 Model

    • View 不会直接操作 Model,只有 Controller 可以操作 Model

  • Model:

    • Model 可以包含业务逻辑,例如数据存储到数据库

    • Model 由 Controller 进行控制,由 View 进行渲染

    • Model 不会主动与 Controller 进行交互,即 Model 无法操作 Controller

    • Model 不会主动与 View 进行交互,即 Model 无法操作 View

MVC 模式包括多种变体

只要稍加更改限制再合理的重新分配职责,我们就可以得到一些 MVC 模式的变体。

例如,Mode-View-Presenter(MVP) 模式和 Model-View-ViewModel (MVVM) 模式。

由于 MVVM 也是一种流行的模式,所以我们展开讲一讲。

MVVM 模式的核心概念简单来说就是打破 View 和 Model 间的隔阂:

  1. View 知道其 Model 并可以直接操作 Model

  2. ViewModel 直接响应用户操作

  3. ViewModel 可以主动通知 View 如何渲染它(Model)

  4. Controller 的职责被重新分配给了 ViewModel

使用 MVC 模式的优势

要说清楚 MVC 的优势,就要先讲传统的 GUI 程序开发模式 —— RAD(Rapid Application Development 快速应用开发) 。

GUI 程序是事件驱动的。只要是 GUI 程序,无论 Web、移动应用还是桌面程序,理论上我们都可以将所有逻辑写在事件处理程序中。

例如,我们可以在一个按钮事件处理程序中,验证文本框文本,获取下拉列表选项值,检查是否选中了复选框,然后与本地文件系统,数据库或 Web 服务进行通信存储数据。

我们将这种方式称为快速应用开发(RAD)。

RAD 仅适用于小型程序,当程序越来越大时,UI 实例之间的关系开始变得混乱。特别是当多个开发人员正在为同一组 UI 编写代码时,越来越难理解来自其他开发人员的逻辑。维护代码,解决代码冲突和修复错误的成本都会上升。

为了避免这些问题,我们可以做两件事:

  1. 将数据和逻辑从事件处理程序分离出来,并将它们集中在某处,以便代码重用

  2. 对于集中式数据和逻辑,将它们分成不同的角色和职责

经过数十年的实验和发展,软件行业发现 MVC(及其变体)一直是一个良好且稳定的解决方案。它可以有效地消除 RAD 在大规模开发中引起的问题。

在大型 GUI 项目中应用 MVC 模式的好处包括:

  1. 健壮:开发人员只能在正确的位置编写代码。他们可以轻松地理解和重用他人的代码

  2. 可测试:UI 很难测试,但与 UI 分离的模型和控制器很容易通过单元测试进行测试。这大大提高了软件质量和开发性能

  3. 可扩展:对于 RAD 开发,添加的 UI 元素越多,UI 形成的网络就越复杂。但 MVC 将应用程序的功能划分为小的垂直支柱。每个支柱由一组控制器,视图和模型组成。扩展程序功能时,我们只需不断添加小支柱并按单元测试用例覆盖代码即可

如何实现 MVC 模式

有三种使用 MVC 及其变体的方法:

  1. RAD + MVC 模式:例如 WinForm 是用于 Windows 开发的 RAD 框架,在编写 WinForm 程序时,你可以手动创建 Model、View 和 Controller,而不是将所有代码都放在事件处理程序中,享受 MVC 模式带来的好处

  2. RAD + MVC 框架:为避免重复造轮子,开发人员为那些单纯的 RAD 框架创建了许多可重用的 MVC 框架。

    1. 例如 WPF 是用于 Windows 开发的 RAD 框架,PRISM 是一个包含基类并实现了 MVVM 模式的基础结构的框架。使用 PRISM 框架时,你可以通过派生基类轻松创建 View、Model 和 ViewModel,而无需从头构建它们

    2. 另一个例子是 Angular 框架。 HTML + JavaScript 是传统的 Web 开发 RAD 框架,但要使用纯 HTML + JavaScript 创建企业级 Web 程序很困难。Angular 是用于 HTML Web 客户端开发的 MVC 框架。一旦你将 HTML 和 Angular 框架结合使用,你的 Web 程序就变成了 MVC 程序

  3. MVC 程序框架:有许多现成的 MVC 程序框架,例如 ASP.NET MVC,ASP.NET Core 和 Spring MVC。使用 MVC 程序框架和使用 RAD + MVC 框架的区别在于:一旦在 MVC 程序框架上构建程序,程序就会被自然地限制为 MVC 程序,你也再无法将其转换为非 MVC 程序。
    例如,当你使用 ASP.NET MVC,ASP.NET Core 或 Spring MVC 创建 Web 程序时,项目构建器会自动应用并搭建 MVC 架构, 你的工作就是不断添加模型,视图和控制器以实现客户的需求