MVP/MVC/MVVM

发展历程

在这里插入图片描述

MVC

1.即Model、View、Controller即模型、视图、控制器。

View:它是提供给用户的操作界面,是程序的外壳;
Model:是程序需要操作的数据和信息;
Controller:接收View层传递过来的指令,选取Model层对应的数据,进行相应操作。

2.举一个现实中的类似的例子,MVC如同一家商铺的运作模式,View层相当于是这家商铺的店面,Model层相当于这家商铺的仓库,Controller层相当于是这家商铺的执行部门。

3.MVC有如下两种模式,不管哪种模式,MVC的通信都是单向的,由图也可以看出,View层会从Model层拿数据,因此MVC中的View层和Model层还是存在耦合的。
在这里插入图片描述
在这里插入图片描述
M和V是完全隔离的,由C作为中间人来负责二者的交互,同时三者是完全独立分开的,这样可以保证M和V的可测试性和复用性,但是一般由于C都是为特别的应用场景下的M和V做中介者,所以很难复用。

Models: 数据层,负责数据的处理和获取的数据接口层。

Views: 展示层(GUI),对于 iOS 来说所有以 UI 开头的类基本都属于这层。

Controller: 控制器层,它是 Model 和 View 之间的胶水或者说是中间人。一般来说,当用户对 View 有操作时它负责去修改相应 Model;当 Model 的值发生变化时它负责去更新对应 View。

优点:

1.代码复用: 三个小模块的V(cell/userInfoView)对外只暴露Set方法, 对M甚至C都是隔离状态, 复用完全没有问题. 三个大模块的MVC也可以用于快速构建相似的业务场景(大模块的复用比小模块会差一些, 下文我会说明).

2.代码臃肿: 因为Scene大部分的逻辑和布局都转移到了相应的MVC中, 我们仅仅是拼装MVC的便构建了两个不同的业务场景, 每个业务场景都能正常的进行相应的数据展示, 也有相应的逻辑交互, 而完成这些东西, 加空格也就100行代码左右(当然, 这里我忽略了一下Scene的布局代码).

扫描二维码关注公众号,回复: 9486311 查看本文章

3.易拓展性: 无论产品未来想加回收站还是防御塔, 我需要的只是新建相应的MVC模块, 加到对应的Scene即可.

4.可维护性: 各个模块间职责分离, 哪里出错改哪里, 完全不影响其他模块. 另外, 各个模块的代码其实并不算多, 哪一天即使写代码的人离职了, 接手的人根据错误提示也能快速定位出错模块.

5.易测试性: 很遗憾, 业务的初始化依然绑定在Scene的生命周期中, 而有些逻辑也仍然需要UI的点击事件触发, 我们依然只能Command+R, 点点点…

缺点

经过上面的改造,MVC架构已经足够清晰了,按照应用场景(一般都是单页面)进行大的拆分,然后在根据业务拆分成小的MVC。不行就接着拆,拆层,拆模块。

但是MVC的最大弊端就是C的代码没法复用,所以能把C层的代码拆出来就尽量拆,我们来看看现在C层的功能还有哪些了

1.作为View和Model的中介者,从model获取数据,经过数据加工,渲染到view上面显示。

2.响应view的点击事件,然后执行相应的业务逻辑。

3.作为view的代理和数据源。

4.暴露接口给SceneVC来驱动自己获取数据。

MVP

1.MVP是从MVC进化而来,即Model、View、Presenter;View和Model同MVC中的M和V,MVP只是将MVC中的Controller变成了Presenter;

2.由上面对MVC的介绍中我们可以得知,MVC中的View层和Model层是存在耦合的,但其实我们不提倡View层与Model层有直接的交互;MVP就是这样一种思想的体现,View层与Model的交互只能通过Presenter;

3.MVP与MVC还有一点不同是,它的通信是双向的,如下图所示,有两个方向:V—>P—>M,M—>P—>V。
让P持有V,P通过V的暴露接口改变V的显示数据和状态,P通过V的事件回调来执行自身的业务逻辑。
让V持有P,V通过P的代理回调来改变自身的显示数据和状态,V直接调用P的接口来执行事件响应对应的业务逻辑。
在这里插入图片描述
第一种方式保持了view的纯粹,只是作为被动view来展示数据和更改状态,但是却导致了P耦合了V,这样业务逻辑和业务展示有糅合到了一起,和上面的MVC一样了。

第二种方式保证了P的纯粹,让P只做业务逻辑,至于业务逻辑引发的数据显示的变化,让view实现对应的代理事件来实现即可。这增加了view的复杂和view对于P的耦合。

在 MVP 中,Presenter 可以理解为松散的控制器,其中包含了视图的 UI 业务逻辑,所有从视图发出的事件,都会通过代理给 Presenter 进行处理;同时,Presenter 也通过视图暴露的接口与其进行通信。

VC层

1.view的布局和组装。

2.view的生命周期控制。

3.通知各个P层去获取数据然后渲染到view上面展示。

controller层

1.生成view,实现view的代理和数据源。

2.绑定view和presenter。

3.调用presenter执行业务逻辑。

model层

1.和MVC的model层类似。

view层

1.监听P层的数据更新通知, 刷新页面展示.(MVC里由C层负责)。

2.在点击事件触发时, 调用P层的对应方法, 并对方法执行结果进行展示.(MVC里由C层负责)。

3.界面元素布局和动画。

4.反馈用户操作。

Presenter层

1.实现view的事件处理逻辑,暴露相应的接口给view的事件调用。

2.调用model的接口获取数据,然后加工数据,封装成view可以直接用来显示的数据和状态。

3.处理界面之间的跳转(这个根据实际情况来确定放在P还是C)。

优点:

1.降低耦合度。

2.模块职责划分明显。

3.利于测试驱动开发。

4.代码复用。

5.隐藏数据。

6.代码灵活性。

缺点:

由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。

MVVM

1.MVVM是由MVP进化而来,MVVM模式基本上与MVP相同,只是把MVP中的P变成了VM,即ViewModel,

2.MVVM中的数据可以实现双向绑定,即View层数据变化则ViewModel中的数据也随之变化,反之ViewModel中的数据变化,则View层数据也随之变化。
在这里插入图片描述

View层:视图展示。包含UIView以及UIViewController,View层是可以持有ViewModel的。

ViewModel层:视图适配器。暴露属性与View元素显示内容或者元素状态一一对应。一般情况下ViewModel暴露的属性建议是readOnly的,至于为什么,我们在实战中会去解释。还有一点,ViewModel层是可以持有Model的。

Model层:数据模型与持久化抽象模型。数据模型很好理解,就是从服务器拉回来的JSON数据。而持久化抽象模型暂时放在Model层,是因为MVVM诞生之初就没有对这块进行很细致的描述。按照经验,我们通常把数据库、文件操作封装成Model,并对外提供操作接口。(有些公司把数据存取操作单拎出来一层,称之为DataAdapter层,所以在业内会有很多MVVM的变种,但其本质上都是MVVM)。

Binder:MVVM的灵魂。可惜在MVVM这几个英文单词中并没有它的一席之地,它的最主要作用是在View和ViewModel之间做了双向数据绑定。如果MVVM没有Binder,那么它与MVC的差异不是很大。

优点:

1.方便测试
在MVC下,Controller基本是无法测试的,里面混杂了个各种逻辑,而且分散在不同的地方。有了MVVM我们就可以测试里面的viewModel,来验证我们的处理结果对不对(Xcode7的测试已经越来越完善了)。

2.便于代码的移植
比如iOS里面有iPhone版本和iPad版本,除了交互展示不一样外,业务逻辑的model是一致的。这样,我们就可以以很小的代价去开发另一个app。(以前做公司iPad的时候就深深感觉到,全部在VC里面是多么的痛苦和重新开发一个没有啥区别)。

3.兼容MVC
MVVM是MVC的一个升级版,目前的MVC也可以很快的转换到MVVM这个模式。VC可以省去一大部分展示逻辑。

缺点:

1.类会增多
每个VC都附带一个viewModel,类的数量*2
viewModel会越来越庞大
我们把逻辑给了viewModel,那势必Model也会变得很复杂,里面的属性和方法越来越多。可能重写的方法比较多,因为涉及到一些数据的转换以及和controller之间的通信。

2.调用复杂度增加
由于数据都是从viewModel来,想想突然来了一个新人,一看代码,不知道真实的模型是谁。比如常用tableview的数据源,一般都是一个数组,如果不断的通过viewModel去取,沟通上没有那么直接。况且每封一层,意味着要写很多代码去融合他们的转换。

发布了45 篇原创文章 · 获赞 157 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/liuyifeng0000/article/details/104574401
今日推荐