前言
做移动端开发和前端开发的人员,对 MVC、MVP、MVVM 这几个名词应该都不陌生,这是三个最常用的应用架构模式,目的都是为了将业务和视图的实现代码分离,从而使同一个程序可以使用不同的表现形式。不过,网上的文章对这方面的解说众说纷纭,其中不乏有些错误的描述,导致有些人应用这些架构模式时陷入一些错误陷阱。本文将追根溯源,力求让大伙对这三个架构模式形成正确认识。
MVC = Model-View-Controller,MVP = Model-View-Presenter,MVVM = Model-View-ViewModel。这三个架构模式,都分别有三个不同的部件,都有相同的 Model 层和 View 层。Model 为模型层,主要管理业务模型的数据和行为;View 为展示层,其职责就是管理用户界面。三个架构模式目的都是为了解耦 Model 和 View,主要不同点就在于三者实现解耦的方案不同。Controller、Presenter、ViewModel,对应着三种不同的解耦方案,三种与 M 和 V 的连接方式。
下面,我们先从 MVC 开始,正确理解了 MVC,另外两个就非常容易理解了。
MVC
MVC 最初被用于 Smalltalk-80,对 MVC 最早的解说来源于一篇论文《Applications Programming in Smalltalk-80(TM):How to use Model-View-Controller (MVC)》,那大概是在 1979 年的时候。该论文对 M-V-C 三个模块以及他们之间的通信都阐述了一些设计细节。
在 MVC 中,对应用程序划分出了三种角色:Model、View、Controller。三者有各自的具体用途和职责,并通过彼此的相互通信实现程序功能。对 MVC 了解不深的人其实存在疑惑,比如,Model 是否等于实体类?业务逻辑是归于 Controller 还是 Model?Model 与 View 具体是如何通信的?这些问题你会在下面的内容找到答案。
MVC 三件套中,最难理解的就是 Model,所以我们先来剖析它。前面我们说过,Model 层主要管理业务模型的数据和行为,它既保存程序的数据,也定义了处理该数据的逻辑,所以 Model = 数据 + 业务逻辑。因此,处理业务逻辑属于 Model 的职责,而非 Controller。从数据的维度来说,可以细分为数据的定义、数据的存储、数据的获取。数据的定义其实就是定义数据结构,一般用实体类来定义,以方便在不同角色间传递数据。数据的存储和获取则可能有几种途径:数据库、网络或缓存等。因此,在实际应用中,一个 Model 并不只是简单的一个对象,而是一个更广泛的层级。很多时候,会将 Model 层再进行分解,比如应用于客户端程序时,可以将 Model 层再细分为业务逻辑层、网络层、存储层等,而实体类其实只是贯穿其中的一种数据结构而已。不过,狭义上,当我们说一个 Model 对象的时候,主要是对外部组件而言的,更多是指这个 Model 对外所提供的数据,并不关心数据从何而来。这可能就是让很多人将 Model 误认为就是实体类的原因。
View 是 MVC 里最好理解的,它会接收用户的交互请求并展示数据信息给用户。一个 View 展示的数据可能只是一个 Model 对象的部分数据,也可能是一个 Model 对象的全部数据,甚至可能是多个 Model 对象数据的组合。在 MVC 里,View 被设计为可嵌套的,使用了组合(Composite)模式来实现。比如,列表视图(ListView)或表格视图(TableView)由每个 Item 组成,每个 Item 又可以由图片、文本、按钮等组成。View 是倾向于可复用的,因此,在实际应用中,倾向于将 View 开发成相对通用的组件。
Controller 层主要担任 Model 与 View 之间的桥梁,用于控制程序的流程。Controller 负责确保 View 可以访问到需要显示的 Model 对象数据,并充当 View 了解 Model 更改的渠道。View 接收到用户的交互请求之后,会将请求转发给 Controller,Controller 解析用户的请求之后,就会交给对应的 Model 去处理。因此,理论上,Controller 应该是很轻的。
MVC 通信机制
其实,MVC 发展至今,三件套之间的通信机制,已经演化出多种通信路径。我们先来看看最初的版本:
所以,一般的交互流程就是:
用户操纵 View,接着生成一个事件。比如用户点击某个按钮,则会生成一个点击事件。 Controller 对象接收事件并解释该事件,即,它应用了策略。该策略可以是请求 Model 对象以更改其状态,或请求 View 以更改其行为或外观。比如,一个注册按钮产生的事件被 Controller 接收之后,那它就会解释该事件,可能先校验用户的输入是否为空,如果为空则请求 View 提示让用户填写用户名和密码等;如果校验通过,那就请求 UserModel 创建新用户。 当状态改变时,Model 对象又通知所有已注册为观察者的对象。如果观察者是 View 对象,则可以相应地更新其外观或行为。还是上面的例子,UserModel 创建新用户成功后,就可以通知观察者们,相应的 View 对象接收到 UserModel 创建新用户成功的通知后,就可以跳转到注册成功后的页面了。
这就是 MVC 最初版本的通信机制,自 1979 年提出之后就被广泛应用在 GUI 程序中。请注意,那时候还没有 HTTP。后来随着微软 ASP.NET MVC Framework 的出现,MVC 也开始被广泛应用于 Web 程序。
变种 MVC
以上版本的 MVC,由于 View 依赖了 Model,实际上减低了 View 的可复用性。那么,如果能将 View 和 Model 彻底解耦,那就可以提高 View 的可复用性了。因此,出现了下面这种变种 MVC:
View 和 Model 不直接通信了,而统一通过 Controller 实现数据的传递。Model 将结果告知 Controller,Controller 再去更新 View。
据我所知,苹果提出了这种变种,在苹果之前,有没有其他人提出该变种,我不得而知。另外,很多 Web 框架的设计也是基于这种变种模式的 MVC 的设计思想,比如 SpringMVC 框架,当然,实际的实现比这个复杂得多,但主要设计思路还是 MVC。
这个变种,很多人会将其误认为另外一个经典架构模式「三层架构」,即他们认为 MVC 就是三层架构。其实,两者是不同的。三层架构分别为:表现层、业务逻辑层、数据访问层。虽然和 MVC 的通信方式很相似,但划分的各层的职责是不同的,最重要的是,两者的使用范围不同。三层架构是从整个应用程序架构的角度来划分的三层,而 MVC 只是表现层里再进行功能划分的设计方案,因此,要说两者之间有什么关联,那也是 MVC 属于三层架构里的一个子集。
接着,我们来看看在实际应用中的 MVC 结构又是怎样的?实际应用中,主要还是用在 App 开发上,以 iOS 为例,请看下图: