iOS--MVC,MVP和MVVM

MVC

MVC,是模型(Model)-视图(View)-控制器(Controller)的缩写,其特点是:M和V相互隔离,通过C连接。

MVC

MVC分工

  • Model: 数据封装,并定义操作和处理该数据的逻辑和计算。为Controller提供数据调度接口。模型对象可以与其他模型对象有一个或多个关系,因此有时应用程序的模型层实际上是一个或多个对象图。
  • View:用户界面,可以响应用户操作。显示来自应用程序模型对象的数据,并允许编辑这些数据。提供简洁的构造方法,确保View的初始化工作完全封闭在View中。
  • 控制器Controller:视图对象与模型对象之间的中介,并管理其他对象的生命周期。具体上则是负责业务逻辑、事件响应、数据获取等工作,管理View Container,负责生成所有的View实例,并放入View Container。Controller不一定就是UIViewController,也可以是任意继承自NSObject的对象。

MVC通信

  • 模型层和视图层相互隔离,通过控制器对象连接。这也是MVC的主要特点。
  • 视图层中创建或修改数据的用户操作通过控制器对象进行通信,并导致模型对象的创建或更新。当模型对象更改(例如,通过网络连接接收到新数据)时,它会通知控制器对象,控制器对象更新相应的视图对象。
  • 视图对象通过应用程序的控制器对象了解模型数据的更改,并将用户发起的更改(例如,通过控制器对象在文本字段中输入的文本)传递给应用程序的模型对象。
  • 控制器对象解释视图对象中的用户操作,并将新的或更改的数据传递到模型层。当模型对象更改时,控制器对象将新模型数据传递给视图对象,以便它们可以显示它。

MVC总结

  • 任务均摊---View和Model确实是分开的,但是View和Controller却是紧密耦合的
  • 可测试性---由于糟糕的分散性,只能对Model进行测试
  • 易用性---与其他几种模式相比最小的代码量。熟悉的人很多,因而即使对于经验不那么丰富的开发者来讲维护起来也较为容易。
  • 臃肿的Controller---随着业务增长和数据的愈发复杂,Controller中的代码会

MVCS

苹果自身就采用的是这种架构思路,从名字也能看出,也是基于MVC衍生出来的一套架构。从概念上来说,它拆分的部分是Model部分,拆出来一个Store。这个Store专门负责数据存取。但从实际操作的角度上讲,它拆开的是Controller。

MVCS如何分工

这算是瘦Model的一种方案,瘦Model只是专门用于表达数据,然后存储、数据处理都交给外面的来做。MVCS使用的前提是,它假设了你是瘦Model,同时数据的存储和处理都在Controller去做。所以对应到MVCS,它在一开始就是拆分的Controller。因为Controller做了数据存储的事情,就会变得非常庞大,那么就把Controller专门负责存取数据的那部分抽离出来,交给另一个对象去做,这个对象就是Store。这么调整之后,整个结构也就变成了真正意义上的MVCS。

分工总结:
视图(View):用户界面
控制器(Controller):业务逻辑及处理
模型(Model):数据存储
存储器(Store):数据处理逻辑

MVCS是基于瘦Model的一种架构思路,把原本Model要做的很多事情中的其中一部分关于数据存储的代码抽象成了Store,在一定程度上降低了Controller的压力。

关于胖Model和瘦Model

胖Model (Fat Model)

cell.obj = obj;

胖Model包含了部分弱业务逻辑。胖Model要达到的目的是,Controller从胖Model这里拿到数据之后,不用额外做操作或者只要做非常少的操作,就能够将数据直接应用在View上。

胖Model做了这些弱业务之后,Controller就会降低一些复杂度,只需要关注强业务代码就行了。众所周知,强业务变动的可能性要比弱业务大得多,弱业务相对稳定,所以弱业务塞进Model里面是没问题的。另一方面,弱业务重复出现的频率要大于强业务,对复用性的要求更高,如果这部分业务写在Controller,类似的代码会洒得到处都是,一旦弱业务有修改(弱业务修改频率低不代表就没有修改),这个事情就是一个灾难。如果塞到Model里面去,改一处很多地方就能跟着改,就能避免这场灾难。
然而其缺点就在于,胖Model相对比较难移植,虽然只是包含弱业务,但好歹也是业务,迁移的时候很容易拔出萝卜带出泥。另外一点,MVC的架构思想更加倾向于Model是一个Layer,而不是一个Object,不应该把一个Layer应该做的事情交给一个Object去做。最后一点,软件是会成长的,FatModel很有可能随着软件的成长越来越Fat,最终难以维护。

瘦Model(Slim Model)

cell.textLabel.text = obj.name;
cell.sunTextLabel = obj.sno;

瘦Model只负责业务数据的表达,所有业务无论强弱一律扔到Controller。瘦Model要达到的目的是,尽一切可能去编写细粒度Model,然后配套各种helper类或方法来对弱业务做抽象,强业务依旧交给Controller。
由于瘦Model跟业务完全无关,它的数据可以交给任何一个能处理它数据的Helper或其他的对象,来完成业务。在代码迁移的时候独立性很强。另外,由于瘦Model只是数据表达,对它进行维护基本上是0成本,软件膨胀得再厉害,瘦Model也不会大到哪儿去。

缺点就在于,由于Model的操作会出现在各种地方,瘦Model在一定程度上违背了DRY(Don’t Repeat Yourself)的思想,Controller仍然不可避免在一定程度上出现代码膨胀。

MVP

MVC的缺点在于并没有区分业务逻辑和业务展示, 这对单元测试很不友好。 MVP针对以上缺点做了优化,它将业务逻辑和业务展示也做了一层隔离,对应的就变成了MVCP。M和V功能不变,原来的C现在只负责布局,而所有的逻辑全都转移到了P层。

MVP中的V在iOS中指的是ViewController和View。MVP将MVC的Controller进行拆分:视图数据逻辑处理部分为P,Controller剩余部分与View合并成V。V和P之间通过Protocol进行通信。

视图数据逻辑:与视图相关的数据处理。例如将NSDate转换成NSString

MVP

MVP实现了各模块的解藕,具有更好的可测试性。但是总体代码量比MVC大。另外,iOS MVC更适用于快速开发,即代码规模较小的项目。因此将简单的MVC的Demo改成MVP,反而会显得笨拙。

这看起来不正是苹果所提出的MVC方案吗?确实是的,这种模式的名字叫做MVC,但是,这就是说苹果的MVC实际上就是MVP了?不,并不是这样的。如果你仔细回忆一下,View是和Controller紧密耦合的,但是MVP的协调器Presenter并没有对ViewController的生命周期做任何改变,因此View可以很容易的被模拟出来。在Presenter中根本没有和布局有关的代码,但是它却负责更新View的数据和状态。

MVP如何分工

MVP是第一个如何协调整合三个实际上分离的层次的架构模式,既然我们不希望View涉及到Model,那么在显示的View Controller(其实就是View)中处理这种协调的逻辑就是不正确的,因此我们需要在其他地方来做这些事情,比如用户输入操作,数据请求,数据处理等等业务逻辑。

分工总结:
视图(View):用户界面
模型(Model):数据存储
展示器(Presenter):数据处理,业务逻辑。

View和Presenter之间是完全解耦的,他们通过接口来交互
View和Presenter是一对一关系,意味着一个Presenter只映射一个View,且他们之间是可以双向交互的。

MVP 总结

  • 任务均摊–我们将最主要的任务划分到Presenter和Model,而View的功能较少(虽然上述例子中Model的任务也并不多)。
  • 可测试性–非常好,由于一个功能简单的View层,所以测试大多数业务逻辑也变得简单
  • 易用性–在我们上边不切实际的简单的例子中,代码量是MVC模式的2倍,但同时MVP的概念却非常清晰

MVVM

在MVP的基础上,将P改成与V双向绑定的VM就变成了MVVM。

image

绑定是一种响应式的通信方式。View拥有ViewModel并监听ViewModel中变量值得变化,当ViewModel某个值变化时,View对象会感知并作出相应展示。可以使用KVO和RAC实现。例如在Label中显示倒计时,是V绑定了包含定时器的VM。
双向绑定在MVVM中指的是V和VM之间相互绑定。例如TextField的text长度达到阈值,另一个Button改变背景颜色。这个过程中首先VM感知V中TextField的text属性长度变化,V感知VM中对应的状态属性。一旦V中TextField的text属性长度超出VM中的阈值,VM中的状态属性改变,触发V中Button的背景色发生改变。

MVVM

MVVM 是 MVC 模式的一种演进,它主要解决了 ViewController 过于臃肿带来的不易维护和测试的问题。其中 ViewModel 的主要职责是处理业务逻辑并提供 View 所需的数据,这样 VC 就不用关心业务,自然也就瘦了下来。ViewModel 只关心业务数据不关心 View,所以不会与 View 产生耦合,也就更方便进行单元测试。

View 是一个壳,它所呈现的内容都需要由 ViewModel 来提供,而 View 又不与 ViewModel 直接沟通,这时就需要 ViewController 来做中间的协调者。

ViewController 持有 View 和 ViewModel,当 VC 初始化时,会让 ViewModel 去取数据,简单来说就是调用 VM 的某个获取数据的方法。

严格来说MVVM其实是MVCVM。从图中可以得知,Controller夹在View和ViewModel之间做的其中一个主要事情就是将View和ViewModel进行绑定。在逻辑上,Controller知道应当展示哪个View,Controller也知道应当使用哪个ViewModel,然而View和ViewModel它们之间是互相不知道的,所以Controller就负责控制他们的绑定关系,所以叫Controller/控制器就是这个原因。
归根结底就是一句话:在MVC的基础上,把C拆出一个ViewModel专门负责数据处理的事情,就是MVVM。然后,为了让View和ViewModel之间能够有比较松散的绑定关系,于是我们使用ReactiveCocoa,因为苹果本身并没有提供一个比较适合这种情况的绑定方法。iOS领域里KVO,Notification,block,delegate和target-action都可以用来做数据通信,从而来实现绑定,但都不如ReactiveCocoa提供的RACSignal来的优雅,如果不用ReactiveCocoa,绑定关系可能就做不到那么松散那么好,但并不影响它还是MVVM。

MVVM如何分工

视图(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的差异不是很大。

因为View、ViewModel以及Model间的清晰的持有关系,所以在三个模块间的数据流转有了很好的控制。

MVVM模式特点

  • MVVM将ViewController视作View
  • 在View和Model之间没有紧密的联系,一般的与View是一对一的关系。
  • ViewModel与View之间是双向交互的
  • 使用 MVVM 最舒服的姿势是搭配现在已经比较成熟的 ReactiveCocoa

MVVM 总结

  • 任务均摊 – 在例子中并不是很清晰,但是事实上,MVVM的View要比MVP中的View承担的责任多。因为前者通过ViewModel的设置绑定来更新状态,而后者只监听Presenter的事件但并不会对自己有什么更新。
  • 可测试性 – ViewModel不知道关于View的任何事情,这允许我们可以轻易的测试ViewModel。同时View也可以被测试,但是由于属于UIKit的范畴,对他们的测试通常会被忽略。
  • 易用性 – 在我们例子中的代码量和MVP的差不多,但是在实际开发中,我们必须把View中的事件指向Presenter并且手动的来更新View,如果使用绑定的话,MVVM代码量将会小的多。

选择

  1. 越复杂的框架耦合度越小,但是开发速度越慢,反之亦然。所以要根据具体项目需求,在不同阶段决定框架。
  2. 如果模式之间存在兼容性,可选择混合开发。

原文https://www.jianshu.com/p/6460021c81a4

分层架构

如按照数据层、网络层、业务层、界面层分层架构

MVC、MVP、MVVM都属于界面层

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容