iOS开发--MVVM-R架构之美
开发软件就像搭建房子,一个好的架构设计,决定着房子搭建的速度、质量和高度。对于移动端开发来说,有常见的MVC
、MVP
、MVVM
和VIPER
等架构模式,这些架构有各自的优缺点,如何寻找合适的架构,这得结合当前的项目情况和期望。笔者这边在综合考虑各种因素之后,决定使用MVVM-R
作为项目的开发架构。下面做下思考的过程。
一个好的架构应该具有的特征:
- 职责单一
- 可测性
- 易用性
Apple 的 MVC
理想状态
MVC.png- Models(模型) - 数据层,提供对应的数据结构。比如 Person 类。
- Views(视图) - 展示层(GUI)。对于 iOS 来说所有以 UI 开头的类基本都属于这层。
- Controller 控制器 - 它是 Model 和 View 之间的胶水或者说是中间人。一般来说,当用户对 View 有操作时它负责去修改相应 Model;当 Model 的值发生变化时它负责去更新对应 View。
现实情况
Apple 的 MVC看上去挺美好的,View 和 Model 之间相互独立的,只是通过 Controller 来相互联系。但是在实际的开发中,往往为了方便,views中还是会引入models进行赋值操作,而且Controller中会写网络数据操作、业务逻辑操作和交互等等代码,显得特别冗肿,不易扩展和后期维护。
对应说需要集成单元测试的来说,因为每个模块耦合太严重基本无法进行。
总结:
- 职责划分:理想状态下,View 和 Model 确实是实现了分离,但是 View 和 Controller 耦合的太厉害
- 可测性:因为划分的不够清楚,所以能测的基本就只有 Model 而已
- 易用:相较于其他模式,它的代码量最少。而且基本上每个人都很熟悉它,即便是没太多经验的开发者也能维护。
如果是对于小项目,只追求开发速度,则MVC可能是较佳的选择。
MVP - 保证了职责划分的(promises delivered) Cocoa MVC
MVP.png- Models(模型) - 数据层,负责处理数据的数据接口层,包括网络请求和数据处理等。
- View/Controller - 展示层和交互层。MVP里面的 View 和 Controller 是耦合紧密的,给Presenter提供视图设置和交互的方法,没有直接拿model进行赋值好操作,保持了很好的独立性。
- Presenter - 它完全不关注 ViewController 的生命周期,里面基本没什么布局相关的代码,它的职责只是通过数据和状态来调用View层提供的方法来更新UI。
MVP 架构拥有三个真正独立的分层,V层通过提供方法,让P层调用和赋值,M层只负责数据提供,具有很好的可测试性,但相对于MVC来说意味着巨大的代码量。
总结:
- 划分: 我们把大部分的职责都分配到了 Presenter 和 Model 里面,而 View 基本上不需要做什么。
- 可测性:简直棒,我们可以通过 View 来测试大部分的业务逻辑。
- 易用: MVP拥有清晰架构思路,但在代码量上会相对做出牺牲。
MVP 架构在 iOS 中意味着极好的可测性和巨大的代码量。
VIPER - 把搭建乐高积木的经验应用到 iOS 应用的设计上
VIPER.pngVIPER的五层职责划分:
- Entity(实体):类似于MVC的Model,是一个纯粹的数据结构对象。
- Interactor(交互器):专门用来负责网络请求和数据处理。
- View/Controller(视图):负责UI的布局和提供交互相关的方法,供Presenter调用。
- Presenter(展示器):负责处理包括调用Interactor进行网络请求,根据状态刷新UI界面,根据用户交互处理相关的业务逻辑等。
- Router(路由): 主要负责 VIPER 模块之间的转场和衔接。
总结:
- 划分:毫无疑问的,VIPER 在职责划分方面是做的最好的。
- 可测性:理所当然的,职责划分的越好,测试起来就越容易。
- 易用:不难想象,上面两点好处都是用维护性的代价换来的。一个小小的任务,可能就需要你为各种类写大量的接口。
如果你的项目较大或未来会很大,VIPER可能是更好的选择。
MVVM - 是 MV(X) 系列架构里面最新兴的,也是最出色的
MVVM.png- Models(模型) - 数据模型,用来存储数据。
- View/Controller(视图) - 视图界面,用来展示UI界面和响应用户交互。
- ViewModel - 链接View和Model的桥梁,处理业务逻辑,更新Model的同时刷新View。
ViewModel可以看做是MVC中对C层的一种优化和升级,把Controller的数据和逻辑处理部分从中抽离出来,用一个专门的对象去管理,这个对象就是ViewModel,是Model和Controller之间的一座桥梁。当MVVM结合绑定模式之后(使用全量级的函数式响应编程框架,比如 ReactiveCocoa、RxSwift 等),它变得越来越受开发者的喜爱,不单单解耦了每个模块,而且还精简了代码,给后期的维护和写单元测试提供了方便。
总结:
- 划分: MVVM 框架里面的 View 比 MVP 里面负责的事情要更多一些。因为前者是通过 ViewModel 的数据绑定来更新自身状态的,而后者只是把所有的事件统统交给 Presenter 去处理就完了,自己本身并不负责更新。
- 可测性:因为 ViewModel 对 View 是一无所知的,这样我们对它的测试就变得很简单。View 应该也是能够被测试的,但是可能因为它对 UIKit 的依赖,你会直接略过它。
- 易用:MVVM的代码量基本跟 MVP 持平,但是在实际的应用当中 MVVM 会更简洁一些。因为在 MVP 下你必须要把 View 的所有事件都交给 Presenter 去处理,而且需要手动的去更新 View 的状态;而在 MVVM 下,你只需要用绑定就可以解决。
MVVM在结合函数式响应编程之后,会变得更加有魅力,但是也会相应的给开发者提出更多的挑战,例如:函数式响应编程在调试方明的问题和对TableView中视图和模型之间如何优雅的绑定问题等等,不过相信这些都不是问题。
MVVM-R架构之美
在了解完MVC
、MVP
、MVVM
和VIPER
架构之后,这里结合项目的需要,觉得MVVM
会更适合现有的项目。所以在此基础上对MVVM
进行了一些小扩展,使各个模块更加的独立可测试,也就是我们一开始看到的这张架构图。
MVVM-R思想:
-
V
:负责视图布局和提供自身需要的数据模型(通过protocol实现),View自身的交互事件,通过delegate代理出去; -
C
:管理生命周期和事件交互; -
M
:只提供数据结构,遵守了View提供的协议; -
VM
:网络请求和业务逻辑处理,界面的显示完全由VM
配置数据源决定; -
R
:处理模块间的跳转。
好处:
- View层完全的独立出来,不需要关心谁给它传递数据,谁来处理交互事件;
- View和Model层实现了完全的解耦;
- ViewModel通过配置数据模型,决定视图的展示。
结合绑定:
- 选一个基于 KVO 的绑定库,比如 RZDataBinding 或者 SwiftBond。
- 使用全量级的 函数式响应编程 框架,比如 ReactiveCocoa、RxSwift 或者 PromiseKit。
这里写了一份MVVM-R架构的Demo,仅供交流学习:
MVVM-R架构之美
感谢:
浅谈 MVC、MVP 和 MVVM 架构模式
iOS 架构模式 - 简述 MVC, MVP, MVVM 和 VIPER
不谈框架,谈细节