前言
与用户界面相关的最大的问题就是大量的凌乱的代码, 表现模式(Presentation Patterns)就是围绕如何移除用户界面的复杂性,让界面更加简洁和可管理而产生的。
表现模式主要包含:
-
用户界面包含负责的逻辑用于维护界面相关对象;
-
包含了应用程序状态的维护;
因此, 目前网络上所称的“MVP、MVC、MVVM架构”,本质上并不完全属于一种架构方式,更确切的说,是一种用户界面和逻辑处理间的一种表现模式 。
(注:本文并不包含iOS的VIPER模式。)
用户界面三要素:状态,逻辑和同步
我们在客户端设计中,用户界面上遇到的三大问题是:状态 (State)、逻辑 (Logic) 、同步 (Synchronization),其中状态是用户界面最关心的问题之一。
主流表现模式一览
目前最常见的表现模式有三种:即MVC模式、MVP模式、MVVM模式。如下图所示:
MVC模式
早在上个世纪70年代,美国的施乐公司(Xerox)的工程师研发了Smalltalk编程语言,并且开始用它编写图形界面的应用程序。而在Smalltalk-80这个版本的时候,一位叫Trygve Reenskaug的工程师设计了MVC图形应用程序的架构模式,极大地降低了图形应用程序的管理难度。而在四人组(Gang of Four: GoF)的设计模式当中并没有把MVC当做是设计模式,而仅仅是把它看成解决问题的一些类的集合。Smalltalk-80 MVC和GoF描述的MVC是最经典的MVC模式。
MVC处理数据、界面的流程如下图:
由图中可以看出,MVC模式中,Model、View均与Controller进行绑定,View接收到用户交互后,将事件传递至Controller,Controller负责业务处理,处理完成之后,将操作Model,并通知View进行更新。此时,View更新需要再从Model处获得数据,获得数据后,完成自身的更新。
(注:网上对MVC实现方式较多,这里只选择了一种较为常用的方式进行阐述。)
MVC的基础:
-
没有Presenter,有一个Controller
-
请求首先到达Controller
-
Controller绑定Model和View
-
逻辑存储在Controller里
MVC优缺点
优点
MVC的方式将业务全部放在了Controller层进行处理,优点是视图层和业务层耦合度低、模块化程度较高,当业务发生变动时,只需调整Controller即可。
缺点
视图与控制器间联系过于紧密,View是强依赖特定的Model的,无法实现组件化,并且视图对模型数据访问效率较低。
MVP模式
因为MVC模式的局限性,后续出现了一种变体,最终演变成MVP的模式。
MVP设计模式有分两种,最先提出来的是马丁·福勒(Martin Fowler),最后于2006年将MVP分成监督控制器Supervising Controller(SC)和被动视图Passive View(PV);概念上来说,两者是相同的,最大的不同在于Presenter能控制的View的程度不同。因SC模式使用较少,因此这里只是简单介绍。
PV模式
在PV模式中,视图上的所有View的数据(具体点来说可以是控件的属性)都会暴露出来,供Presenter来调用。View的任务就是简单地在需要的时候把数据呈现出来,或者把数据提供给Presenter。涉及到一些UI逻辑的,无论复杂与否都与View本身无关。UI逻辑是Presenter的任务,这种方式使得View以一种很轻量级的形式存在,UI逻辑放到了Presenter里面进行处理,方便了对UI逻辑做测试。
MVP-PV模式处理数据、界面的流程如下图:
MVP-PV的基础:
-
状态存储在View里。
-
所有UI逻辑存储在Presenter里。
-
View与Model完全隔离。Presenter负责处理Model和View以及额外的数据同步任务。
-
Presenter知道View
-
View不知道Presenter
SC模式
SC模式中,Presenter会把一部分简单的同步逻辑交给View自己去做,Presenter只负责比较复杂的、高层次的UI操作,所以可以把它看成一个Supervising Controller
MVP-SC的基础:
-
状态存储在View里
-
Presenter包含复杂的展示逻辑。简单的UI绑定逻辑通过使用绑定技术来完成,例如WPF绑定和Silverlight绑定。任何复杂性有Presenter类处理
-
Presenter知道View
-
View不知道Presenter
-
View视图使用由WPF和Silverlight提供的绑定技术与模型链接
MVP的优缺点
优点
-
模型与视图完全分离,修改视图不会影响模型。
-
可以更高效地使用模型,因为所有的交互都发生在Presenter内部
-
可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
-
逻辑放在Presenter中,可以脱离用户接口来测试这些逻辑
缺点
-
视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更
MVVM模式
MVVM模式最早由微软提出,并将其运用在WPF和SilverLight中。与此同时,在技术层面,WPF也带来了 诸如Data Binding(数据绑定)、Dependency Property(依赖属性)、Routed Events(路由事件)、Command(命令)、DataTemplate(数据模板)、ControlTemplate(控制模板)等新特性。MVVM模式其实是MVP模式与WPF结合的应用方式时发展演变过来的一种新型架构模式。它立足于原有MVP框架并且把WPF新特性糅合进去,以应对客户日益复杂的需求变化。
(注:MVVM的模式是马丁·福勒所提出的Presentation Model的模式的一种演变。)
MVVM模式处理数据、界面的流程如下图:
从图中看出,它和MVP的区别貌似不大,只不过是Presenter层换成了ViewModel层,还有一点就是View层和ViewModel层是相互绑定的关系,这意味着当你更新ViewModel层的数据的时候,View层会相应的变动UI。
我们很难去说MVP和MVVM这两个MVC的变种孰优孰劣,还是要具体情况具体分析。
MVVM的基础:
-
ViewModel是基础
-
状态储存在ViewModel里
-
逻辑存储在ViewModel里
-
ViewModel代表一个UI的抽象视图
-
ViewModel不知道View
-
View知道ViewModel
-
View与Model完全隔离
-
使用DataBinding
MVVM的优缺点
优点:
-
提高可维护性。解决了MVP大量的手动View和Model同步的问题,提供双向绑定机制。提高了代码的可维护性。
-
简化测试。因为同步逻辑是交由Binder做的,View跟着Model同时变更,所以只需要保证Model的正确性,View就正确。大大减少了对View同步更新的测试。
缺点:
-
ViewModel引用了View,从而导致ViewModel无法重用于其他View
-
过于简单的图形界面不适用
-
对于大型的图形应用程序,视图状态较多,ViewModel的构建和维护的成本都会比较高。
-
数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的。
-
并没有解决View层过重的问题,仅仅去掉了数据绑定,尤其对一些复杂业务逻辑的页面。
MVVM的进化:MVP-VM模式
在MVVM模式之后,微软在MVP的基础上,提出了一种新的模式MVP-VM,具体内容可参考微软官网文章"MVPVM Design Pattern - The Model-View-Presenter-ViewModel Design Pattern for WPF"。把MVPVM这种模式,拆分成为Model-View-Presenter-ViewModel,这种模式将MVP和MVVM两者的特点结合了起来,并且将ViewModel进行拆分,提升可拔插化以提高可复用性,松耦合和尽量小的接口可以给予最大的可复用性,使得组件能重组使用。
(注:后面会提到Model分领域模型和视图模型,如无特殊说明,下文的Model均属于领域模型,MVP-VM的ViewModel和MVVM的ViewModel概念不尽相同。)
以Android为例,在MVP-VM作者的介绍中:
-
Model层,和MVP中的Model是类似的。即PO或者DO
-
View层,依然是由Activity/Fragment来担当,不同的是需要实现ViewModel的观察者接口,来实现View的动态更新
-
Presenter层,如上图所示,Presenter作为核心,连接着M、V、VM
-
VM层,和MVVM中的VM是类似的,只是为了让VM可以重用。不再和特定的View绑定,而且不再直接对Model进行操作
因此,Android DataBinding的出现,让MVP-VM这种模式在Android上出现了新的思路。
MVP-VM模式处理数据、界面的流程如下图:
从图中可以发现,MVP-VM中的Model包含了领域模型(Domain Model)和视图模型(View Model);领域模型是一个对象层,是对现实世界逻辑、数据和你应用程序所处理的问题的抽象。视图模型通常只包含领域模型的一个子集,而且只包含界面上所需要的属性。此外Domain Model是数据加上行为的组合体,是由复杂的变量类型组成的并且具有层次。业务的处理主要由Presenter来进行承载。因此,该模式将业务、视图、领域模型和视图模型进行分离,更有层次感。当然缺点也显而易见,对于逻辑功能较为简单的页面来说,将其进行拆分会增加整体结构的复杂性,没有使用MVP或者MVVM来的更加简单轻便。
MVP-VM的基础
按照微软的定义,严谨的MVP-VM模式应该遵循以下定义
-
Presenter是基础(MVP)
-
状态储存在ViewModel里(MVVM)或者Presenter中(MVP)
-
逻辑存储在Presenter里(MVP)
-
ViewModel代表一个UI的抽象视图(MVVM)
-
ViewModel不知道View(MVVM)
-
View知道ViewModel(MVVM)
-
View不知道Presenter(MVP) ViewModel不知道Presenter(MVP-VM)
-
View与Domain Model完全隔离(MVVM)
-
Presenter知道Domain Model(MVP)
-
Presenter知道View(MVP-VM)
-
Presenter负责处理ViewModel以及额外的数据同步任务(MVP-VM)
-
ViewModel中不存在任何逻辑处理(MVP-VM)
各表现模式下状态、逻辑和同步关系
选取了目前最常用的集中表现模式,各模式下,状态、逻辑和同步的处理如下表所示:
结语
综上所述,MVC、MVP、MVVM、MVP-VM本身就是一种循序渐进的过程,后者解决了前者的问题,将前者的缺点变成了自己自己的优点。但最终都是由技术选择驱动的,每一种模式并无孰好孰坏之分,都拥有不同适用的场景。
参考文档
《MVVM for .NET Winforms – MVP-VM (Model View Presenter - View Model) Introduction》
《MVC vs. MVP vs. MVVM》
《MVC,MVP 和 MVVM 模式如何选择?》
《MVC,MVP,MVVM之异曲同工》
《MVP的PV模式与SC模式》
《UI的設計模式MVP模式–Supervising Controller》
《MVP(SC),MVP(PV),PM,MVVM 和 MVC 表现模式架构对比》
《展示模式架构比较MVP(SC),MVP(PV),PM,MVVM和MVC》
《MVC、MVP、MVVM三种区别及适用场合》
《MVPVM in Action, 谁告诉你MVP和MVVM是互斥的》
《浅谈Android架构之MVP,MVVM》