前端MV*框架之经典MVC

96
integrate
2015.09.18 14:38* 字数 1857

一、学习背景

由于公司业务日益庞大,很多老项目需要维护,由于这些项目的前端基本都是jQuery+jQuery plugins搞定的,编写的代码可谓是:无组织、无纪律,导致前端维护成本越来越高,为了解决这一难题,决定引入前端MV*框架。从浏览器兼容性、与其他组件方便集成的角度考虑,最终选择了backbone.js。因为之前接触过AngularJS,backbone.js我只看了一天文档,就能开发实际项目了;但是有个问题一直耿耿于怀,由于backbone.js没有明确指出自己的架构模式,所以它不属于MVC、MVP、MVVM中的任何一种,而是介于它们之间的某个变种,这一点让我极度郁闷,因为这导致我无法精确的组织JavaScript代码。而这一问题的根本原因是我对MV*架构模式的理解不够深刻,所以我决定:先将MVC、MVP、MVVM的定义与区别理解透彻,再回过头来审视backbone.js。

MVC是一种架构模式,说白了就是一种组织代码的方式,将代码根据职责划分成三块区域,这样的好处很明显:易于阅读、便于维护。回想一下没有引入MV*框架前的那一坨JavaScript代码,我相信大部分人都会表示:我碰都不想碰了。就算你引入了模块加载框架(requirejs、seajs等),你的代码仍然是“凌乱”的,只不过范围缩小到模块内部而已,前端MV*框架就是为了解决这个问题出现的。

二、经典MVC

2.1 MVC诞生

20世纪80年代,mvc作为smalltalk-80(传说中的“面向对象编程之母”)的一个类库走进人们的视野。那个年代浏览器还没出现,计算机的图形用户界面(GUI)还相当的简陋。为了将UI组件代码从业务逻辑代码中剥离出来,人们尝试对应用程序进行分层,产生了最初的MVC模式。当今的MVC(本文称为MVC的变种)已经与经典MVC大相径庭,由于经典MVC的某些特征并不适合如今的富客户端应用(后面会有解释),所以从某种意义上来说,经典MVC已经消失了,本文的描述针对的是经典MVC。

2.2 经典MVC的工作流程

经典MVC根据职责将代码划分为三个区域:Model(模型)、View(视图)、Controller(控制器)。不考虑特殊场景,大部分的工作流程是这样的:

"经典MVC"
"经典MVC"

首先从M、V、C各自的职责说起:

  • Model:代表业务逻辑层,它无视表现层的存在,只专注处理业务。
  • Controller:接受用户的输入,将输入转为相应的命令,执行进一步的操作。
  • View:向用户呈现展示的信息,与M建立观察者模式,根据M的改变自动重新渲染。

首先需要说的是,不要以浏览器的角度理解这个流程,因为那个时代浏览器还未出现。一个完整的MVC的工作流程是这样的:

  1. 首先C接受用户的刺激。
  2. (流程①)C将这种刺激转化为某种命令去调用M的接口,对M执行更新操作。
  3. (流程②)M发送状态改变的通知给V(由观察者模式完成)。
  4. (流程③)V调用M的接口获取最新数据,重新渲染V(由观察者模式完成)。

从调用流程我们发现经典MVC有以下几个特征:

  1. C与V共同组成一个表现层,即一个UI组件,两者是无法独立存在的,所以没有实质上的分离,这点与如今的MVC变种有很大区别。
  2. C与V没有直接的调用关系,各自处理自己的事务。
  3. 引入观察者模式实现数据绑定,C没有直接更新V,而是去更新M,然后通过观察者模式对V进行更新。由于一个M可以对应多个UI组件,当某个特定的C更新M时,会引起相关的多个V同时更新,这对于开发复杂的用户界面非常便利。
  4. 成功将“表现层(C+V)”从“业务逻辑层(M)”剥离出来。

2.2 经典MVC的缺陷

2.2.1 观察者模式的缺陷

观察者模式在给开发者带来便利的同时,也带来了一个问题,那就是:很难通过跟踪代码来获悉程序的流程走向,这直接导致了程序复杂度的提高,所以过多的使用观察者模式会使程序变的不易理解。

2.2.2 特殊表现层逻辑的尴尬位置

随时用户对图形界面的要求越来越高,GUI变得越来越复杂,表现层的逻辑已经不仅仅是将M的数据直接显示到屏幕上那么简单。我们需要对M的数据进行进一步的加工处理后才能呈现给用户。经典MVC的时代,图形用户界面是非常简单的,所以MVC能满足大部分场景的需求,就算有那么一小部分特殊的表现层逻辑(M数据的加工处理),也被放到M里进行处理了,虽然污染了M的纯度,但是影响并不大。但是对于当代的富客户端应用来说,这种“特殊表现层逻辑”是非常庞大的,如果都塞进M里,这显然是不能接受的。

2.2.3 smalltalk的对策

基于smalltalk-80 MVC的开发者也意识到了MVC的短板,他们采用的策略是对V进行拓展,将V拓展为一个全新的对象,它既包含V的全部内容(包括取代V,与M建立观察者模式),又含有对M数据进行加工处理的逻辑代码,他们把这种全新的对象叫作:Presentation Model。而这一切的改变都是为了更彻底的将“表现层”与“业务逻辑层”分离。

三、总结

经典MVC总起来说有两个关键点:分离表现层、通过观察者模式进行数据同步。虽然MVC已经不能满足当代富客户端应用的需求,但是它的两个关键点却被传承了下来,影响了一系列的MVC变种,比如MVP、MVVM等,而这些MVC变种也正是为了满足富客户端的需求进化而来,下篇文章介绍MVP与MVVM。

参考文献

<a href="https://en.m.wikipedia.org/wiki/Model–view–controller">wikipedia Model-view-controller</a>
<a href="http://martinfowler.com/eaaDev/uiArchs.html#ModelViewController">Martin Fowler GUI Architectures</a>
<a href="http://c2.com/cgi/wiki?ModelViewControllerHistory">Model View Controller History</a>

JavaScript框架篇
Web note ad 1