我与MVVM的恩怨情仇

原创 2016年06月01日 11:52:54

记得面试那会儿,因为有一点MVVM的使用经验,跟面试官谈了一下。我的观点是,ViewModel封装展示逻辑,不包含接口调用,接口调用封装在另一个类里面(比如xxx API),然后在controller调用API类拿到数据后由ViewModel封装好给到视图层。当时得到的评价是,这不算是MVVM,还是在对Controller瘦身的层次上。

来到公司后发现,这里的MVVM是在ViewModel里包含了网络调用,读写缓存,业务逻辑,展示逻辑等等,几乎是Controller里面抽取了UIView,剩下的所有逻辑的集合。特意搜索了一些iOS MVVM的文章,的确是把众多逻辑都放在ViewModel里。但是一直觉得这种做法只是把臃肿从Controller移到了ViewModel,而且明显违背单一职责原则,ViewModel变成一个大杂烩。

今天看到一篇文章,MVVM 不是那么好,观点大致是:ViewModel引入太多的逻辑,MVVM只是转移和缓解了MVC的问题,无法彻底解决。讨论MVVP的文章看了不少,其中不乏抨击MVVM的,但这篇直入我心扉,也给了我不少启发。忍不住吐槽一下现在项目的MVVM。

现在的MVVM有什么问题?

  1. ViewModel职责太多。号称MVVM分离了UI和逻辑,但一个应用只分离UI和逻辑是远远不够的,”逻辑”里往往会有很多”子逻辑”,这里子逻辑现在全部堆在ViewModel里,造成了一个万能的ViewModel。导致一个ViewModel可能有非常多的状态和接口,迟早变成变成Massive ViewModel,重蹈Controller的覆辙。
  2. MVVM试图把UIViewController跟UIView看成同一个东西。Controller知道所有的View,它能响应整个页面视图的事件,在视图响应链里扮演重要角色,Controller有生命周期函数,业务层的调用入口往往是在这里。这些特性使Controller理所当然地充当胶水代码。这些特性即无法转移,也是独一无二的。所以Controller注定跟UIView不一样。即便在MVVM中Controller也负责ViewModel的生命周期管理。所以想把胶水抽到ViewModel中,把Controller薄化成UIView往往是不彻底的。
  3. 难以测试。最近在部门在推单元测试,由于之前有一些单元测试经验,毛遂自荐做了一次推动者。发现有些ViewModel测试无从下手,原因是状态复杂,内部逻辑太多。现在定义的ViewModel是封装逻辑提供给Controller使用,天生会积极隐藏Controller用不到的逻辑。按照测试原则,只测公有方法,但是内部又有一堆关键的逻辑。

他山之石,可以攻玉,看看其它语言和框架的MVVM是怎样的。

AngularJS 2.0版本听说大变样了,这里只说2.0以前的版本。AngularJS的MVVM跟iOS传统的MVVM大不一样,网络调用往往是封装在一个Service里面,并不包含在ViewModel,ViewModel($scope)非常薄,主要用来做数据绑定和事件转发。用AngularJS的经验不多,但是在一两个项目实践中,感觉AngularJS的MVVM比iOS传统的MVVM划分更合理一些。

那么,MVVM究竟该怎么玩?我的答案是:不必拘泥于既有的模式。

记得某大神说过,架构就是不停地拆分。拿到需求后,拆分成各个子功能,对应App各个子模块,然后子模块再细分,接着整理依赖关系,上浮下沉,自然就形成了分层。所以设计最关键的,不是拘泥于应用MVC或者MVVM或者MVP,而是学会拆分,把职责分离,形成高内聚的模块,并设计松耦合的接口。其中的利器便是SOLID原则,个人最常考虑的是S(单一职责)O(开闭原则),能把这两点做好,已经很可贵,正在努力攻关中。。。

重新思考了一下App架构大致的模样,细化后的模块,大致都可以被划分成几种类型,比如很多功能都需要一个网络请求的子模块,一个加工数据的模块。总结了一下,大致会有以下几种:API,Store,LogicModel,ViewModel,Controller,View。API封装网络,Store封装本地持久化,LogicModel封装业务逻辑(内存操作,跟后端架构中的领域层类似),ViewModel封装展示逻辑,Controller的职责还是胶水,它可能会持有各种对象,并负责协助对象通信。这些应该是大多数功能模块划分时都需要考虑的子模块。至于这么划分后还是MVVM吗?不要再思考这个问题,程序设计是一个创造性的活动,就像招术不是武术的根本,MVVM,MVP,MVC也不是设计的根本,设计原则才是。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

ios中解析获取pdf目录及相对应的页数

//目录下的名字字典     if (CGPDFDictionaryGetDictionary(pdfDic, "Outlines", &namesDictionary))     {     ...
  • sadlike
  • sadlike
  • 2013年07月22日 09:45
  • 1952

iOS强制切换横屏、竖屏

切换横竖屏最直接的方式是调用device的setOrientation方法。但是从sdk3.0以后,这个方法转为似有API,如果要上AppStore的话,要慎用!     if ([[U...
  • Chuekup
  • Chuekup
  • 2013年03月04日 18:26
  • 6399

三英战吕布:360与金山、腾讯、百度之间的恩怨情仇

三英战吕布:360与金山、腾讯、百度之间的恩怨情仇 近日,腾讯金山等企业发布联合声明反对360不正当竞争,而360称腾讯发声明是为转移视线,将公布更多证据。这是继《狗日的腾讯》的“攻击谩...

《从DOS和UNIX两个方向开始谈现代操作系统的恩怨情仇》

《从DOS和UNIX两个方向开始谈现代操作系统的恩怨情仇》 混沌未分天地乱,茫茫渺渺无人见。自从盘古破鸿蒙,开辟从兹清浊辨。覆载群生仰至仁,发明万物皆成善,这来自于中国四大名著之一的《西游记》。他说...
  • z612425
  • z612425
  • 2015年05月06日 23:53
  • 716

winXP,win7,Ubuntu12.04的恩怨情仇

winXP,win7,Ubuntu的恩怨情仇     1) 最近想在winXP系统下装一个Ubuntu,由于之前有过直接在硬盘上安装    Ubuntu的经历,所以这次打算再直接装一下。用Eas...

MSVC 与 CRT 之间的恩怨情仇

很久没有写程式设计入门知识的相关文章了,这篇文章要来谈谈程式库 (Library) 连结,以及关于 MSVC 与 CRT 之间的种种恩怨情仇。 如果你使用的作业系统是 Linux、Mac 或其他非 ...
  • zxh2075
  • zxh2075
  • 2013年11月25日 09:26
  • 713

接口和抽象类的恩怨情仇!

接口是什么,抽象类又是什么,有了抽象类,我们为什么还要有接口呢?
  • AbriYou
  • AbriYou
  • 2017年06月05日 06:10
  • 85

== 与 equals 的恩怨情仇

这篇讲明 == 与 equals 的区别

【学习日记】抽象类与接口的“恩怨情仇”

抽象类abstract是一个用来表示抽象的修饰符,可以用来修饰类与对象,抽象与具体是相对的,所以抽象类与抽象方法是不能实例化的。 抽象类和抽象方法的声明形式: abstract class Cl...

盗墓笔记之缘起与大结局∶张起灵与汪藏海的500年恩怨情仇

从网上无意间搜到的,觉得着实不错,发上来和大家分享:   元末明初,大约是500年前,汪藏海被东夏抓去给万奴王修墓。此时与14代万奴王共生的蚰蜒已经到了生命的尾期。万奴王临死前命令其贴身侍卫张起灵为...
  • Cituses
  • Cituses
  • 2017年07月25日 13:47
  • 166
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:我与MVVM的恩怨情仇
举报原因:
原因补充:

(最多只允许输入30个字)