MVC 架构

随着现代浏览器越来越强大,其功能也越来越强大,使用 JavaScript 构建成熟的 Web 应用不仅可行,而且越来越受欢迎。根据 HTTP Archive趋势,部署的 JavaScript 代码大小在过去一年中增长了 45%。

JS 传输大小和 JS 请求

随着 JavaScript 越来越受欢迎,我们的客户端应用比以前复杂得多。应用开发需要多个开发者的协作。在新的 Web 应用时代,编写可维护且可重复使用的代码至关重要。Chrome 应用也不例外,拥有丰富的客户端功能。

设计模式对于编写可维护且可重复使用的代码非常重要。模式是一种可重复使用的解决方案,可以应用于软件设计中的常见问题(在本例中为编写 Chrome 应用)。我们建议开发者遵循 MVC 模式将应用分离为一系列独立的组件。

在过去几年里,我们开发了一系列 JavaScript MVC 框架,例如 backbone.jsember.jsAngularJSSenchaKendo UI 等。虽然它们都有自己的独特优势,但每种都遵循某种形式的 MVC 模式,目标是鼓励开发者编写结构化程度更高的 JavaScript 代码。

MVC 模式概览

与标准 JavaScript 相比,MVC 具有架构优势,有助于您编写更有条理、更易于维护的代码。这种模式已在多种语言和几代编程人员中得到使用并进行了广泛的测试。

MVC 由三部分组成:

模型视图控制器

模型

Model 是存储应用数据对象的位置。该模型对视图和控制器一无所知。当模型发生更改时,通常会通知其观察者发生了更改。

为了进一步了解这一点,我们使用待办事项列表应用,这是一个用于跟踪任务列表的简单单页 Web 应用。

模型视图控制器

此处的模型表示与每个待办事项关联的属性,例如说明和状态。新的待办事项创建完毕后,会存储在模型的实例中。

查看

View 是向用户显示的内容,以及用户与应用互动的方式。视图由 HTML、CSS、JavaScript 和模板(通常为模板)创建。Chrome 应用的这一部分可以访问 DOM。

例如,在上面的待办事项列表 Web 应用中,您可以创建一个视图,为用户呈现待办事项列表。用户还可以通过某种输入格式输入新的待办事项;但是,视图不知道如何更新模型,因为这是控制器的工作。

控制器

控制器是决策者,也是模型与视图之间的“粘合剂”。当模型发生更改时,控制器会更新视图。此外,它还会向视图添加事件监听器,并在用户操作视图时更新模型。

在待办事项列表 Web 应用中,当用户将某个项标记为已完成时,系统会将点击操作转发到控制器。控制器会修改模型,将清单项标记为已完成。如果需要持久保留数据,它还会对服务器进行异步保存。在富客户端 Web 应用开发(例如 Chrome 应用)中,将数据持久保留在本地存储空间中也很重要。在这种情况下,控制器还会负责将数据保存到客户端存储空间,例如 FileSystem API

MVC 设计模式有一些变体,例如 MVP(模型-视图-演示者)和 MVVP(模型-视图-ViewModel)。即使采用所谓的 MVC 设计模式本身,传统 MVC 模式与采用各种编程语言的现代解释之间还是存在一些差异。例如,一些基于 MVC 的框架会让视图观察模型中的更改,而其他基于 MVC 的框架则让控制器处理视图更新。本文并不侧重于比较各种实现,而是重点说明要关注的方面以及编写现代 Web 应用的重要性。

如果您有兴趣了解更多信息,建议您参阅 Addy Osmani 的在线书:Learning JavaScript Design Patterns

总而言之,MVC 模式为应用开发者带来了模块化,并可实现以下功能:

  • 可重复使用且可扩展的代码。
  • 将视图逻辑与业务逻辑分离开来。
  • 允许负责不同组件(例如界面层和核心逻辑)的开发者同时执行多项工作。
  • 更易于维护。

MVC 持久性模式

使用 MVC 框架实现数据持久性有许多不同的方法,每种方法都有不同的权衡。在编写 Chrome 应用时,您可以选择具有 MVC 和持久性模式的框架,这些框架让您感觉很自然,符合您的应用需求。

模型自行持久化 - ActiveRecord 模式

ActiveRecord 模式在服务器端框架(如 Ruby on Rails)和客户端框架(如 Backbone.jsember.js)中很受欢迎,它负责确保模型本身的持久性,并且通常通过 JSON API 实现。

与让模型处理持久性的略微不同之处在于引入了 Store 和 Adapter API 的单独概念。存储区、模型和适配器(在某些框架中称为代理)可以相互手动完成。存储区是保存加载的模型的代码库,它还提供了创建、查询和过滤其中包含的模型实例等功能。

适配器或代理接收来自存储区的请求,并将其转换为对持久性数据层(例如 JSON API)执行的适当操作。这在现代 Web 应用设计中非常有趣,因为您经常与多个持久性数据层(例如远程服务器和浏览器的本地存储)进行交互。Chrome 应用提供了用于客户端存储的 Chrome Storage APIHTML 5 FileSystem API

优点:

  • 易于使用和理解。

缺点:

  • 很难测试,因为持久性层是“内置”到对象层次结构中的。
  • 让不同的对象使用不同的持久性存储很困难(例如,FileSystem API、indexedDB 和服务器端)。
  • 在其他应用中重复使用模型可能会造成冲突,例如在两个不同的视图之间共享一个 Customer 类,每个视图都希望保存到不同的位置。

控制器执行持久性

在这种模式中,控制器保留对模型和数据存储区的引用,并负责使模型持久保留。该控制器会响应加载、保存、删除等生命周期事件,并向数据存储区发出命令以提取或更新模型。

优点:

  • 可以向控制器传递模拟数据存储区来根据其编写测试,这样更易于测试。
  • 只需使用不同的数据存储区构建控制器,即可在多个数据存储区中重复使用同一模型。

缺点:

  • 代码维护起来可能更复杂。

AppController 实现持久性

在某些模式中,有一个监督控制器负责在 MVC 和 MVC 之间导航。例如,AppController 确定“返回”按钮将客户端从编辑屏幕(包含 MVC widget/格式)移动到设置屏幕。

在 AppController 模式中,AppController 通过以下方式响应事件并更改应用的当前屏幕:向数据存储区发出调用以加载所需的任何模型,并为该屏幕构建所有匹配的视图和控制器。

优点:

  • 将持久性层移至堆栈中更高的位置,以便轻松对其进行更改。
  • 不会污染 DatePickerController 等较低级别的控制器,需要了解持久性。

缺点:

  • 应用的每个“页面/屏幕”现在都需要大量样板来编写或更新:Model、View、Controller、AppController。

MVC 对于设计 Chrome 应用至关重要。我们建议您使用以下符合 CSP 标准的 MVC 框架来编写安全且可伸缩的 Chrome 应用:

实用资源

线上

图书