一直想聊聊这个话题,也有朋友跟我留言,让我讲讲MVVM,只可惜一直没整明白,不敢轻易下笔。针对MVVM,网上有很多不错的文章,比如MVVM介绍、被误解的 MVC 和被神化的 MVVM以及Look at MVVM from a different perspective等等
文章前我想先提几个问题
- MVVM到底是什么?它和MVC有什么区别?
- MVVM中VM到底是个什么角色?它和Controller或者Manager有什么区别?
- ViewController在MVVM中扮演怎样角色?Api数据请求放在哪里?数据流向如何?
MVVM简介
关于MVVM,相信大家或多或少都有了解。引用MVVM介绍文中一图
受MVC或MVP架构的影响,对MVVM最初印象以为这是一个以viewmodel为核心,处理View和Model的开发架构。于是乎在原有MVC的基础上,创建了一个所谓的viewmodel对象,然后把ViewController中的代码移到viewmodel中,在viewmodel里面处理View以及Model的所有逻辑。毕竟大家都在说MVVM可以为ViewController瘦身,这ViewController就剩创建viewmodel的代码,嗯,够瘦身,这就是MVVM!
慢慢的,发现有什么地方不对,哪里不对?第一想法就是ViewController的定位,View?不是,Controller?也不是!毕竟它就创建viewmodel,好像与View、Model也没啥关系。抛开ViewController不谈,突然发现这样的viewmodel、Model以及View不就是MVC,一个以viewmodel为中心的MVC!
错在哪里
核心问题就在于对viewmodel角色的定位不清!基于MVVM设计思路,viewmodel存在目的在于抽离ViewController中展示业务逻辑,而不是替代ViewController,其它视图操作业务等还是应该放在ViewController中实现
既然不负责视图操作逻辑,viewmodel中就不应该存在任何View对象,更不应该存在Push/Present等视图跳转逻辑。因此,viewmodel中绝不应该存在任何视图操作相关的代码
viewmodel做啥
很简单,处理视图展示逻辑,viewmodel负责将数据业务层提供的数据转化为界面展示所需的VO。其与View一一对应,没有View就没有viewmodel
比如,数据业务层传递一个含有性别属性sex的DO对象,0表示男, 1表示女。viewmodel的职责就是将其转化为展示层可显示的VO对象
viewmodel和View一起组成DDD(Model-Driven Design)领域驱动架构体系中的Presentation展示层。在iOS中,数据流向可以表示为viewmodel->ViewController->View,ViewController负责连接VO及其对应的View对象
领域驱动设计
领域驱动设计(DDD)对于安卓童鞋可能非常熟悉,有兴趣的童鞋可以参考这篇文章,本文不做过多讲解,借用其描述介绍几个名词
- VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来
- DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体
- PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性
- Domain:领域驱动层,是用户与数据库交互的核心中转站,控制用户数据收集,控制请求转向等
MVVM架构中,viewmodel连接视图View和数据业务Model层,而Domain和Data数据持久层共同组成整个Model层。完整结构如图所示
Model并不表示Model
MVVM架构中的M,并不表示Model对象,而是表示整个数据业务层,对应DDD架构中的Domain层以及数据Data层。业务开发中,一般考虑Api或者DB对象,极少考虑Domain层设计,也不会区分DO或者PO对象。笼统定义Model ,将其传递给展示层viewmodel,久而久之,Model对象承载的信息越来越多,更有甚者,在Model中处理业务逻辑,导致项目维护成本增加,代码中出现if..else的概率也会越来越大