iOS 中 MVC、MVP、MVVM、VIPER 等技术框架的选型与实践
前言
架构和设计模式是我们工作和面试中都比较重要的一个环节,
在
iOS
开发中,当你开始做项目,或者梳理完需求后,你要做的并不是马上写下你的第一行代码,而是需先设计好整个项目的技术框架今天,我将全面介绍开发中主流的技术框架
MVC
、MVP
、MVVM
模式以及非主流的VIPER
模式,并实例讲解MVP
模式,希望大家可以有点收获。
1. 选型技术框架给项目带来的好处
可扩展性
架构良好的项目具有良好的扩展能力。 比如一年后如果有新的需求,需要添加新功能,好的架构设计会让会让开发更容易,可扩展性更强。
可维护性
功能开发完成后,如果有需求更改的请求,好的架构可以随时响应。 架构良好的应用程序更易于维护。
可靠性
应用程序应该能够正确执行预期的功能,并且可以容忍用户犯错误或以意外方式使用软件。 通常即使遇到一些异常情况或者边界条件,系统也应继续正常运行。
其他好处
模块化功能
使得程序模块化,即:内部的高聚合、模块之间的低耦合
提高开发效率
开发人员只需专注于某一点(视图显示、业务逻辑 / 数据处理)
提高测试效率
方便后续的测试 & 定位问题
切记:不要为了设计而设计,也不要过度设计,否则反而会提高开发成本和开发量
2. 如何进行技术框架的选型
架构模式上,每种模式都各有优点,也各有局限性。越高级的模式复杂性越高,实现起来也越难,学习成本越高。最近火热的微服务架构,比起 MVC,复杂度不知增加了多少倍。
在实际项目中思考架构时,也不会想着要用哪种模式,我只思考现阶段,以现有的人力资源和时间资源,如何才能更快更好地完成需求,适当考虑下如何为后期扩展或重构做准备。
技术选型,决策关键不在于每种技术方案的优劣如何,而在于你团队的水平、资源的多寡,要根据实际情况选择最适合你们当前阶段的架构方案。当团队拓展了,资源也充足了,肯定也是需要再重构的,到时再思考其他更合适更优秀的方案。
2. iOS 开发的主流技术框架
主要有
MVC
、MVP
、MVVM
3 种主流的模式以及VIPER
偏小众的模式下面,我将详细 & 具体的介绍上述几种技术框架
2.1 MVC
下图显示了 Model View Controller 三者之间的关系。
Model
模型是数据所在的地方。 诸如持久性,模型对象,解析器,管理器和网络代码之类的东西都在这里。
View
视图层是应用程序的外观。 它的类通常不包含任何特定于域的逻辑,因此通常可以重用。 例如,UILabel 是一个在屏幕上显示文本的视图,它是可重用和可扩展的。
Controller
通过委派模式在 View 和模型之间进行中介。 在理想情况下,控制器实体将不知道其处理的具体视图,它将通过协议与抽象进行通信。 一个经典的示例是 UITableView 通 UITableViewDataSource 协议与其数据源进行通信的方式。
MVC 存在的问题:
分层设计弱,控制器几乎在这里处理所有事情,它处理业务逻辑和表示逻辑,包括更新 UI,动画等。
由于业务逻辑,表示逻辑和 UIKit 成员在控制器中混合在一起,因此难以进行单元测试。 可测试的类不应依赖任何 UIKit 成员无法轻易扩大规模。
难以维护,当项目成长时,控制器将变得混乱和沉重。
2.2 MVP
MVP 模式是从“Model-View-Controller”模式派生的,但存在一些差异。 MVP 模式具有一个称为 Presenter 的新层,这是 MVP 的主键。
这里的 View 与 Model-View-Controller 模式中的 View 相同,除了 View 不应直接与 Model 交互,View 只能与 Presenter 交互。
Model 也与 Model-View-Controller 模式中的模型相同,但是 Model 也不能直接与 View 交互,它应该仅与 Presenter 交互
Presenter 是 Model-View-Presenter 模式引入的新层,如图所示,Presenter 是一个中间层,用于处理 View 和 Model 之间的通信。 它解决了许多 MVC 问题,例如可测试性,可维护性,可伸缩性。
优点
降低耦合
模块职责划分明显
利于测试驱动开发
代码复用
隐藏数据
代码灵活性
缺点
视图的渲染放在 Presenter 中,所以视图和 Presenter 的交互会过于频繁。如果 Presenter 过多地渲染视图,往往会使得它与特定的视图的联系过于紧密。
Presenter
层的职责:
一般而言,它应该处理表示逻辑。 它负责显示什么内容以及何时基于。
通常,
Presenter
也可以处理业务逻辑,但是在具有巨大业务逻辑的应用程序中,您应该为业务添加业务层。 另外,架构模式不是圣经,您可以根据自己的应用程序及其业务进行自定义。Presenter
充当 View 和 Model 之间的中间层,因此它可以处理从控制器接收的输入并对它们进行一些操作,如重新格式化数据,验证输入或过滤数据等。 此外,当模型更改时,演示者还应更新 Controller 以便更新 View。
2.3 MVVM
MVVM(Model-View ViewModel)架构模式与 iOS 中实现的 MVC 类似,但提供了更好的 UI 和表示逻辑分离。 这种解耦导致 iOS 中的视图控制器类更清晰,灵活且易于阅读 MVVM 模式源自与 MVP 相同的 Model-View-Controller 模式,它也具有与 MVP 相同的组件和关系,但是 Presenter 层被 ViewModel 层取代,并且 View 与 ViewModel 之间的通过数据绑定实现通信。
下图显示了 Model View ViewModel 三者之间的关系。
Model
和 View
与 MVP 模式相同,现在让我们重点关注ViewModel
什么是ViewModel
?它的职责是什么?ViewModel 是 MVVM 体系结构模式的核心,并提供了业务/表示逻辑与 View / ViewController 之间的连接。视图(UI)通过将输入数据(由模型定义)传递给 ViewModel 来响应用户输入。反过来,ViewModel 评估输入数据,并根据业务逻辑工作流以适当的 UI 呈现进行响应。
除了以下两点,ViewModel 的职责与 MVP 中的 Presenter 相同:
通过数据绑定范例将 ViewModel 与 View 紧密结合,使用最广泛的是
Reactive Programming
,有很多框架可以实现Reactive Programming
,例如RxSwift
,ReactiveCocoa
和Bond
。ViewModel 应该随时表示 View 的当前状态,这意味着 ViewModel 是一个从字面上表示 View 的模型(例如,如果我们的登录屏幕包含两个用于用户名和密码的 UITextfields。那么,ViewModel 应该具有两个 String 属性,分别代表用户名 Textfield 和密码 TextField),当您使用任何响应式框架或任何数据绑定方法来实现它时,这非常容易。
优点
双向绑定时,当 Model 变化时,View-Model 会自动更新,View 也会自动变化。
View 的功能进一步的强化,具有控制的部分功能。
控制器的功能大部分移动到 View 上处理,大大的对控制器进行了瘦身。
缺点
数据绑定使得 Bug 很难被调试。
数据双向绑定不利于代码重用。
大的模块,model 很大,不利于内存的释放。
2.4 VIPER
VIPER
是我们最后一个要介绍的框架,这个框架比较有趣的是它不属于任何一种 MV(X) 框架。
到目前为止,你可能觉得我们把职责划分成三层,这个颗粒度已经很不错了吧。现在 VIPER 从另一个角度对职责进行了划分,这次划分了 五层。
Interactor(交互器) - 包括数据(Entities)或者网络相关的业务逻辑。比如创建新的 entities 或者从服务器上获取数据;要实现这些功能,你可能会用到一些服务和管理(Services and Managers):这些可能会被误以为成是外部依赖东西,但是它们就是 VIPER 的 Interactor 模块。
Presenter(展示器) - 包括 UI(but UIKit independent)相关的业务逻辑,可以调用
Interactor
中的方法。Entities(实体) - 纯粹的数据对象。不包括数据访问层,因为这是
Interactor
的职责。Router(路由) - 负责
VIPER
模块之间的转场
实际上 VIPER 模块可以只是一个页面(screen),也可以是你应用里整个的用户使用流程(the whole user story)- 比如说「验证」这个功能,它可以只是一个页面,也可以是连续相关的一组页面。你的每个「乐高积木」想要有多大,都是你自己来决定的。
如果我们把 VIPER
和 MV(X)
系列做一个对比的话,我们会发现它们在职责划分上面有下面的一些区别:
Model(数据交互)的逻辑被转移到了 Interactor 里面,Entities 只是一个什么都不用做的数据结构体。
Controller/Presenter/ViewModel 的职责里面,只有 UI 的展示功能被转移到了 Presenter 里面。Presenter 不具备直接更改数据的能力。
VIPER 是第一个把导航的职责单独划分出来的架构模式,负责导航的就是 Router 层。
如何正确的使用导航(doing routing)对于 iOS 应用开发来说是一个挑战,MV(X) 系列的架构完全就没有意识到(所以也不用处理)这个问题。
3. MVP 和 MVVM 的比较
首先让我们同意,它们两者几乎相同,并且它们之间的差异并不大,有人认为,MVVM
是MVP
的响应式版本。
MVP 和 MVVM 之间的主要区别总结如下
Presenter
具有其视图的引用,即使该引用作为协议通过也仍然是演示者的依赖关系之一。将引用作为协议类型传递并不意味着 Presenter 没有对 View 的引用。协议方法仅用于测试和重用目的,而 ViewModel 没有对其视图的任何引用,这使 ViewModel 易于测试和重用。Presenter
处理表示逻辑和业务逻辑(如果我们没有业务层),而视图模型执行相同的操作,但是视图模型精确地保存当前视图状态。MVVM 应该使用响应式框架(RxSwift,ReactiveCocoa,Bond 等)以响应式方式编写,而 MVP 不需要数据绑定。
4. 如何选择合适的架构
如果非要选择的话,我的建议是根据个人或团队的理解和能力,选择适合自身的架构模式。具体建议如下:
对于简单的、改动不大的项目,那就不要用设计模式或者架构方法,只需要将每个模块封装好,方便调用即可。
对于偏向展示型的 App,绝大多数业务逻辑都在后端,App 主要功能就是展示数据,交互等,建议使用 MVVM。
对于工具类或者需要写很多业务逻辑 App,使用 MVP 或者 MVVM 都可。
如果想通过一个项目去学习架构和设计模式,建议用 MVC 然后在此基础上慢慢挖掘改进。最后你可能发现,改进的最终结果可能就变成了 MVP,MVVM。
最后,架构设计的目的是提升代码的可读性、可维护性,而不是过度提升代码复杂性,更不是随意引入某某框架。Google 官方也说了,万能架构是不存在的。如果是已经非常稳定的项目,则没有必要重新架构。只不过作为开发人员,还是要保持对新技术的敏感性。
版权声明: 本文为 InfoQ 作者【行者】的原创文章。
原文链接:【http://xie.infoq.cn/article/1e943f0a0b2cab2c708148bb9】。文章转载请联系作者。
评论