iOS架构模式初探

一个项目的架构模式选择有多种,Apple推荐的MVC模式是被大多数开发者所选用的,后来又慢慢了解到MVP,MVVM,以及VIPER。
下面是我对这些模式特性以及适用情景的理解,欢迎各位大神一起探讨。

一个好的架构应该具备的特点:

  1. 任务均衡分摊给具有清晰角色的实体
  2. 可测试性通常都来自与上一条(对于一个合适的架构是非常容易)
  3. 易用性和低成本维护

MVC。MVP。MVVM都把应用中的实体分为以下三类:

  • Models–负责主要的数据或者操作数据的数据访问层,可以想象 Person 和 PersonDataProvider 类。
  • Views–负责展示层(GUI),对于iOS环境可以联想一下以 UI 开头的所有类。
  • Controller/Presenter/ViewModel–负责协调 Model 和
    View,通常根据用户在View上的动作在Model上作出对应的更改,同时将更改的信息返回到View上。

将实体划分可以更好的理解它们之间的关系,进行复用(尤其是对于View和Model),进行独立的测试。

1.最通用的MVC
最传统的MVC下的View没有任何界限,只是简单的在Controller中呈现model的变化。传统的MVC之间相互都有通信,耦合度很高,复用性较低。
苹果官方推荐的MVC希望Controller是一个介于View 和 Model之间的协调器,所以View和Model之间没有任何直接的联系。Controller是一个最小可重用单元,三者之间关系如下:
MVC

而事实上,如果严格按照采用这种格式,将业务逻辑和数据转换到Model,View的最大的任务就是向Controller传递用户动作事件。ViewController最终会承担一切代理和数据源的职责,还负责一些分发和取消网络请求以及一些其他的任务。
事实上我们很多次会把给视图控件赋值的逻辑写在View里,由View直接来调用Model,比如
cell.productModel = tadArray[indexPath.row];
如果严格遵守MVC的话,就会把对cell的设置放在 Controller 中,不向View传递一个Model对象,这样就会大大增加Controller的体积,使Controller变得更加臃肿。而Controller和View的高度耦合,也使单元测试变得更加艰难,需要有足够的创造性来模拟View和它 们的生命周期。

2.实现了Cocoa愿景的MVP
MVP是第一个如何协调整合三个实际上分离的层次的架构模式。
这里写图片描述
看起来跟MVC没什么区别,但在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–而不需要使用自动化的测试工具。 我们甚至可以在Model和View都没有完成时候,就可以通过编写Mock Object(即实现了Model和View的接口,但没有具体的内容的)来测试Presenter的逻辑。 在MVP里,应用程序的逻辑主要在Presenter来实现,其中的View是很薄的一层。因此就有人提出了Presenter First的设计模式,就是根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。在后面,根据需要再随便更改View,而对Presenter没有任何的影响了。 如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。 在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model–这就是与MVC很大的不同之处。
就MVP而言,UIViewController的子类实际上就是Views并不是Presenters。这区别使这种模式的可测试性变强,但代码量更大,降低了开发速度,因为必须要做一些手动的数据和事件绑定。
MVP的特性:

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

    3.最新的MVVM

    除了固有的 Model和View外,VM即是ViewModel。
    这里写图片描述
    如上图所示,它和MVP模式非常像,都将ViewController视为View,只是将原controller里的逻辑处理移到了ViewModel里, 所谓”逻辑部分”可以是各种delegate,网络请求,缓存,数据库,coredata等等。View 和Model之间没有紧密的联系,也有像监管版本的MVP那样的绑定功能,但这个绑定不是在View和Model之间而是在View和ViewModel之间。
    所谓绑定除了自己实现还有两种选择:

  • 基于KVO的绑定库如 RZDataBinding 和 SwiftBond
  • 完全的函数响应式编程,比如像ReactiveCocoa、RxSwift或者 PromiseKit
    提到MVVM就会联想到最近大热的ReactiveCocoa,主要是因为ReactiveCocoa能更好的发挥MVVM的特点。详细请戳:iOS开发之ReactiveCocoa下的MVVM

(我们很容易想到把 UITableViewDataSource和UITableViewDelegate 的代码提取出来放到一个单独的类.
这里有个demo把cell的生成, cell行高, 点击等等抽象出来了 .还可以用block的形式使得函数能够回调,感兴趣可下载看看)
在MVVM下的三个特性评估:
- 任务均摊 –
在例子中并不是很清晰,但是事实上,MVVM的View要比MVP中的View承担的责任多。因为前者通过ViewModel的设置绑定来更新状态,而后者只监听Presenter的事件但并不会对自己有什么更新。
- 可测试性 –
ViewModel不知道关于View的任何事情,这允许我们可以轻易的测试ViewModel。同时View也可以被测试,但是由于属于UIKit的范畴,对他们的测试通常会被忽略。
- 易用性 –
在我们例子中的代码量和MVP的差不多,但是在实际开发中,我们必须把View中的事件指向Presenter并且手动的来更新View,如果使用绑定的话,MVVM代码量将会小的多。

MVVM集合了上述方法的优点,由于在View层的绑定它不需要其他附加代码来更新View,且测试性依然很强。

4.VIPER–把LEGO建筑经验迁移到iOS app的设计
VIPER是iOS应用干净的架构的应用程序。VIPER对于图层,交互,实体和路由来说是一个backronym。干净的架构将一个应用程序的逻辑结构划分为不同的层的责任,提供明确的应用程序逻辑和有关导航代码的位置。这使得它更容易隔离依赖项(如数据库)和测试之间的边界的交互层。
VIPER在责任划分层面进行了迭代,VIPER分为五个层次:
这里写图片描述

  • 交互器 – 包括关于数据和网络请求的业务逻辑,例如创建一个实体(数据),或者从服务器中获取一些数据。为了实现这些功能,需要使用服务、管理器,但是他们并不被认为是VIPER架构内的模块,而是外部依赖。
  • 展示器 – 包含UI层面的业务逻辑以及在交互器层面的方法调用。
  • 实体 – 普通的数据对象,不属于数据访问层次,因为数据访问属于交互器的职责。
  • 路由器 – 用来连接VIPER的各个模块。
    与MV(X)系列相比,VIPER在任务均摊方面有一些不同:

  • Model 逻辑通过把实体作为最小的数据结构转换到交互器中。

  • Controller/Presenter/ViewModel的UI展示方面的职责移到了Presenter中,但是并没有数据转换相关的操作。
  • VIPER是第一个通过路由器实现明确的地址导航模式。

    VIPER模块可以是一个屏幕或者用户使用应用的整个过程–想想认证过程,可以由一屏完成或者需要几步才能完成,取决于模块大小。
    由上可见,VIPER的任务均摊特性很突出,而很好地分布性就有更好的可测试性,但是易用性表现就弱了,维护成本较高,必须为很小功能的类写出大量的接口。所以现在应用VIPER架构还为时过早大材小用,现在维护起来确实是有些不合理,考虑一些更为简单的模式可能会更好。

通过以上的对比分析,想必你跟我一样对应用的架构有了一定的认知和了解,不再因为MVC所以MVC了,其实选择架构是一个根据实际情况具体分析利弊的过程,当然,在同一个应用中也可以根据页面需要选择多种不同的架构,但并没有必要对那些在MVC模式下运转良好的页面进行重构,因为二者是可以并存的。

猜你喜欢

转载自blog.csdn.net/nefertari_yinc/article/details/50519737