天天看点

[架构]MVC/MCP/MVVM三个框架模式

MVC框架模式

MVC是一种框架模式而非设计模式,GOF把MVC看作是3种设计模式:观察者模式、策略模式与组合模式的合体,而核心是观察者模式。

[架构]MVC/MCP/MVVM三个框架模式

MVC框架模式图

[架构]MVC/MCP/MVVM三个框架模式

角色说明

[架构]MVC/MCP/MVVM三个框架模式

模式说明

当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。

MVC(Model-View-Controller),它将应用程序划分为三个部分:

  1. 模型Model: 数据块(用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法)
  2. 视图View: 用户界面
  3. 控制器Controller: 业务逻辑控制器(M和V之间的连接器,用于控制应用程序的流程,及页面的业务逻辑)

优缺点

优点

  1. 模块化了,将业务逻辑、数据处理与界面显示进行分离

缺点

  1. View依赖特定的Model,无法组件化
  2. 主要业务逻辑都在Controller中,Controller会变得很重
  3. View和Controller紧耦合,如果脱离Controller,View难以独立应用(功能太少)

在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同View显示。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

MVP框架模式

[架构]MVC/MCP/MVVM三个框架模式

MVP框架模式图

[架构]MVC/MCP/MVVM三个框架模式

角色说明

[架构]MVC/MCP/MVVM三个框架模式

模式说明

MVP(Model-View-Presenter)跟MVC很相像,最大的差别是Model和View之间不进行通讯,都是通过Presenter完成。

Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。Presenter与View的交互是通过接口来进行的。

View向Presenter发起调用请求,Presenter修改Model,Model修改完成后通知Presenter,Presenter再调用View的相关接口刷新界面。这样,View就不需要监听具体Model的变化了,只需要提供接口给Presenter调用就可以了。

优缺点

优点

  1. MVP模式会解除View与Model的耦合,有效的降低View的复杂性,我们可以修改视图而不影响模型;同时又带来了可扩展性、可测试性。
  2. 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。

缺点

  1. 在不使用接口的情况下,视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更。

比较

MVC的耦合性还是较高的,View可以直接访问Model,导致3者之间构成了回路。所以两者的主要区别是,MVP中View不能直接访问Model,需要通过Presenter发出请求,View与Model不能直接通信。

MVVM框架模式

[架构]MVC/MCP/MVVM三个框架模式

MVVM框架模式图

[架构]MVC/MCP/MVVM三个框架模式

模式说明

VM层:ViewModel,即 View的数据模型和Presenter的合体

ViewModel大致上就是MVP的Presenter和MVC的Controller了,而View和ViewModel间没有了MVP的界面接口,而是直接交互,用数据“绑定”的形式让数据更新的事件不需要开发人员手动去编写特殊用例,而是自动地双向同步。数据绑定你可以认为是Observer模式或者是Publish/Subscribe模式,原理都是为了用一种统一的集中的方式实现频繁需要被实现的数据更新问题。

MVVM与MVP非常相似,唯一区别是View和ViewModel进行双向绑定,两者之间有一方发生变化则会反应到另一方上。

优缺点

  1. 低耦合,视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  2. 可重用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
  3. 可测试,界面向来是比较难于测试的,而现在测试可以针对ViewModel来写。
  4. 比起MVP,MVVM不仅简化了业务与界面的依赖关系,还优化了数据频繁更新的解决方案,甚至可以说提供了一种有效的解决模式。

DataBinding

DataBinding是谷歌官方发布的一个框架,顾名思义即为数据绑定,是MVVM模式在Android上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。DataBinding其实并没有实现新的API来完成双向绑定,只是对原有API的封装,如findViewById()和setText(),亦或是click事件,这些都被框架隐藏起来了。至于这些事件的触发,例如View层接收到点击事件并通知ViewModel层,则是使用发布订阅模式实现的,如下图:

[架构]MVC/MCP/MVVM三个框架模式

DataBinding

每当View层更改时,ViewModel层通过订阅收到通知;每当ViewModel层更改时,View层也会通过订阅收到通知,这样就实现了双向绑定。

这里可能会出现一个循环问题,假设其中某一层A改变,那么另外一层B得到通知随之改变,这会导致A层得到通知,A层也改变,循环往复出现问题。

DataBinding通过前后数据对比来决定是否更新,假设View层需要更新文本信息(如TextView),则DataBinding会对比当前的文本和更新的文本,如果不一致则进行更新操作;如果相同,则不做任何操作。其他的控件也有类似的判定操作,这样就解决了数据双向绑定中的循环问题。

三种模式出现的初衷

MVC模式的出现

为解决程序模块化问题,于是MVC模式出现了:将业务逻辑、数据处理与界面显示进行分离来组织代码,即分成M、V、C层;

MVP模式的出现

但M、V层还是有相互交叉、隔离度不够,于是出现了MVP: 隔离了MVC中的 M 与 V 的直接联系,将M、V层更加隔离开来;

MVVM模式的出现

为了更加分离M、V层,于是出现了MVVM: 使得V和M层之间的耦合程度进一步降低,分离更为彻底。

区别

先说一下三者的共同点,也就是Model和View

  • Model就是领域模型,数据对象,同时,提供外部对应用程序数据的操作的接口,也可能在数据变化时发出变更通知。Model不依赖于View的实现,只要外部程序调用Model的接口就能够实现对数据的增删改查。
  • View就是UI层,提供对用户的交互操作功能,包括UI展现代码及一些相关的界面逻辑代码。

三者的差异在于如何粘合View和Model,实现用户的交互操作以及变更通知。M-V-X本质都是一样的,重点还是在于M-V的桥梁,要靠X来牵线。

[架构]MVC/MCP/MVVM三个框架模式
  • Controller接收View的操作事件,根据事件不同,或者调用Model的接口进行数据操作,或者进行View的跳转,从而也意味着一个Controller可以对应多个View。Controller对View的实现不太关心,只会被动地接收,Model的数据变更不通过Controller直接通知View,通常View采用观察者模式监听Model的变化。
  • Presenter,与Controller一样,接收View的命令,对Model进行操作;与Controller不同的是Presenter会反作用于View,Model的变更通知首先被Presenter获得,然后Presenter再去更新View。一个Presenter只对应于一个View。根据Presenter和View对逻辑代码分担的程度不同,这种模式又有两种情况:Passive View(被动视图)和Supervisor Controller(监控员)。
  • ViewModel,注意这里的“Model”指的是View的Model,跟上面那个Model不是一回事。所谓View的Model就是包含View的一些数据属性和操作的这么一个东东,这种模式的关键技术就是数据绑定(data binding),View的变化会直接影响ViewModel,ViewModel的变化或者内容也会直接体现在View上。这种模式实际上是框架替应用开发者做了一些工作,开发者只需要较少的代码就能实现比较复杂的交互。

MVP和MVVM完全隔离了Model和View,但是在有些情况下,数据从Model到ViewModel或者Presenter的拷贝开销很大,可能也会结合MVC的方式,Model直接通知View进行变更。在实际的应用中很有可能你已经在不知不觉中将几种模式融合在一起,但是为了代码的可扩展、可测试性,必须做到模块的解耦,不相关的代码不要放在一起。

分化是一种需求的必然结果,但却没有个一个确定的结果。MVC顺着需求把UI相关的工作分化成了三份,这点经过实践证明无可厚非。但是它们的三角关系却被一些人认为带来了一些问题,或者应该说他们有“更好的”解决方案。在MVC,当你有变化的时候你需要同时维护三个对象和三个交互,这显然让事情复杂化了。