六、MVC-VS设计模式

Reference:
App Architecture

MVC+VC是MVC的一种变体,所不同的是它将view state视为model层的一部分,用view state model进行存储,ViewController观察view state model,并且相应地更新 view 层级。

MVC+VS中的反馈回路

MVC+VS对MVC的改进在于:提供了一种一致的处理view state变更的方法,让view state可以被持久化,同时对view state的数据管理也变成了单向数据流。

MVC+VC中view state的数据流

除了对view state的处理变成了单向数据流,MVC+VS中对view state使用model抽象还带来了三点好处:

  1. Model通过接口和程序其余部分交流,在有需要时,对接口中的实现进行替换,并不会影响到接口和对接口的使用
  2. Model为action提供了单一的事实来源,让重构和测试可以只关注单一的某个点
  3. 对Model的观察和响应可以被不同的action重用,所以结构的扩展性会更好

关于view state model有两点需要特别注意

  • 虽然view state model文档(数据)model是同一层抽象,并遵循相同的使用规则,但还是应该保持分离,这是因为文档(数据)与view state生命周期并不相同
  • view state model中仅仅是存储了代表view state的简单值,并不包含对数据的变形(这部分逻辑依然写在ViewController中),这是其和MVVM中的view-model最本质的区别

一、MVC+VS的实现

1.构建

与MVC和MVVM中先构建ViewController不同,MVC+VS中需要首先构建view state,然后在view state所触发的观察回调中,去构建ViewController,再由ViewController构建其他部件。但由于view state的观察者就是ViewController,因此在view state的构建之前需要至少一个ViewController,所以第一个ViewController即Root ViewController比较特殊,它在view state之前构建。

2.将View连接到数据

MVC+VS从view state model和文档(数据)model中拉取数据,并订阅这些数据,然后将这些数据关联到view上去。需要注意的是MVC+VS的标准模式是,文档(数据)model对象的标识应该存储在view state model中,这就意味着对文档(数据)model的观察是依赖于view state的,对文档(数据)model的观察必须在对view state model的观察之后。

绝大多数应用场景中,ViewController的文档(数据)model的标识符在ViewController的生命周期中都不会更改,但如果有需要改变的情况,必须在view state model的观察回调里面,重新加载文档(数据)model,并重新创建创建对文档(数据)model的观察。

3.更改Model

更改model的回路MVC+VS和MVC中是一样的:view将action传递给ViewController,ViewController直接更改model,同时ViewController中观察了model,当model变更时做相应的view更新。

4.更改View State

MVC+VS为view state的处理添加了一条和文档数据处理相似的路径:view将action传递到ViewController,ViewController更改view state model,同时ViewController中观察了view state model,当view state model变更时做相应的view更新。

####状态恢复
MVC+VS的架构在view state model中维护了完整的view state,将view state model序列化保存,再根据其构建ViewController和ViewController的层级,即可完成状态恢复,状态恢复时的代码路径和初始构建的代码路径是一致的。

5.测试

MVC+VS和MVC中都使用集成测试,但实现上有很大的不同,第一个不同在于MVC+VS中不再需要先构建ViewController树,而是构建Root ViewController和view state model即可,包括ViewController树在内的其余部分都将作为view state的响应被自行创建出来。这样就可以通过提供view state model作为根ViewController的输入,以特定的状态构建出app的一个新的实例(状态恢复)。

MVC+VS书写测试时的另外一个不同在于研究对action的响应时,MVC中研究对action的响应,可能需要等待动画或其他异步更改的完成,MVC+VS中“对于view action的响应所造成的view state更改” 与 “view state更改引起view层级中的更新”这两段路径的测试是可以分离开的。也就是说可以直接验证view state来确保某个action确实对数据进行了合适的变更,而不需要等待action执行动画并且最终更新view,这部分路径的测试代码会变得好写很多。至于view state的变更引起view更新的这段路径,则可以为它编写单独的测试。

二、MVC+VS的优缺点

MVC+VS最大的好处在于为view state变更的通讯创建了一致的机制,对view state使用观察者模式也保证了UI的同步;同时原本发生在ViewController之间的通讯,现在也可以通过view state来完成;最后,因为view state model上维护了完整的view state,所以也能很方便的完成状态日志、状态恢复、时间旅行调试等功能。

MVC+VS在实践中一个比较麻烦的问题在于并不是总能在UIKit更新view层级之前捕获到view state的变化,比如NavigationController返回按钮和返回手势所引起的层级变动,这需要我们设置NavigationController的delegate,在页面层级变动完成,而这种变动又不是由view state的变更所引起时(由返回按钮和返回手势所引起),去对view state进行更新和处理,其他类似的情况也需要我们去添加代码支持。

三、MVC+VS架构的优秀经验

1.数据的依赖注入

在对象初始化的时候将数据作为参数传递进去就叫依赖注入,在MVC+VS中为ViewController设置初始的view state model时便是选用的这种方式,这样可以避免直接访问单例,更方便书写测试,同时这也比初始化时先设置为nil再等之后提供非nil的方式更加简单,这种方式也可以用于其他基于ViewController的模式中。

2.全局View State通讯

但view state会被多个ViewController或view共享时,使用单例来保存view state以提供全局的view state通讯,往往比在这些ViewController或view的共同祖先中保存view state更加的简单直接,它还不需要去考虑ViewController或view层级间的通讯管道。

3.简化本地View State

可以把一个简化版的MVC+VS应用到MVC的单个ViewController中:将部分view state抽象出来,用一个对象存储(字典或自定义类),将这个对象设置为ViewController的属性,并对这个属性进行观察,在该属性变更的时候对view做这部分view state的更新,这种方式在一定程度上能缓解复杂的ViewController中view state的交互问题。

-------------This article is over, thank you for reading -------------