iOS MVC、MVVM、MVP架构模式浅浅析

声明:本文不少部分是对王巍App 架构一书的学习笔记,若有侵权,请告知程序员

咱们须要决定在 app 中如何执行下列任务:

构建 — 谁负责构建 model 和 view,以及将二者链接起来? 更新 model — 如何处理 view action? 改变 view — 如何将 model 的数据应用到 view 上去? view state — 如何处理导航和其余一些 model state 之外的状态?编程

App 的本质是反馈回路

“View 层和 model 层须要交流。因此,二者之间须要存在链接。假设 view 层和 model 层是被清晰地分开,并且不存在没法解耦的联结的话,二者之间的通信就须要一些形式的翻译:” 缓存

V和M交互逻辑.png

“当一个 view action 被送到 model 层时,它会被转变为model action (或者说,让 model 对象执行一个 action 或者进行更新的命令)。这种命令也被叫作一个消息 (特别在当 model 是被 reducer 改变时,咱们会这么称呼它)。将 view action 转变为 model action 的操做,以及路径上的其余逻辑被叫作交互逻辑。”架构

“当 view 依赖于 model 数据时,通知会触发一个 view 变动,来更改 view 层中的内容。这些通知能够以多种形式存在:Foundation 中的 Notification,代理,回调,或者是其余机制,都是能够的。将 model 通知和数据转变为 view 更改的操做,以及路径上的其余逻辑被叫作表现逻辑。”app

MVC

“MVC 的核心思想是,controller 层负责将 model 层和 view 层撮合到一块儿工做。Controller 对另外两层进行构建和配置,并对 model 对象和 view 对象之间的双向通信进行协调。因此,在一个 MVC app 中,controller 层是做为核心来参与造成 app 的反馈回路的:”框架

“图中的虚线部分表明运行时的引用,view 层和 model 层都不会直接在代码中引用 controller。实线部分表明编译期间的引用,controller 实例知道本身所链接的 view 和 model 对象的接口”工具

MVC.png

MVC 中有两个最多见的问题学习

  • 观察者模式失效 第一个问题是,model 和 view 的同步可能失效。当围绕 model 的观察者模式没有被完美执行时,这个问题就会发生。常见的错误是,在构建 view 时读取了 model 的值,而没有对后续的通知进行订阅。另外一个常见错误是在变动 model 的同时去更改 view 层级,这种作法假设了变动的结果,而没有等待 model 进行通知,若是 model 拒绝了这个变动的话,就会发生错误。这类错误会使得 view 和 model 不一样步,奇怪的行为也随之而来。
  • 肥大的 View Controller View controller 须要负责处理 view 层 (设置 view 属性,展现 view 等),可是它同时也负责 controller 层的任务 (观察 model 以及更新 view),最后,它还要负责 model 层 (获取数据,对其变形或者处理)。结合它在架构中的中心角色,这使得咱们很容易在不经意间把全部的职责都赋予 view controller,从而迅速让程序变得难以管理。

MVC构建测试

  1. 构建 App 对象负责建立最顶层的 view controller,这个 view controller 将加载 view,而且知道应该从 model 中获取哪些数据,而后把它们显示出来。Controller 要么显式地建立和持有 model 层,要么经过一个延迟建立的 model 单例来获取 model。在多文档配置中,model 层由更低层的像是 UIDocument 或 NSDocument 所拥有。那些和 view 相关的单个 model 对象,一般会被 controller 所引用并缓存下来。
  2. 更改 Model 在 MVC 中,controller 主要经过 target/action 机制和 (由 storyboard 或者代码进行设置的) delegate 来接收 view 事件。Controller 知道本身所链接的 view,可是 view 在编译期间却没有关于 controller 接口的信息。当一个 view 事件到达时,controller 有能力改变自身的内部状态,更改 model,或者直接改变 view 层级。
  3. 更改 View” “在咱们所理解的 MVC 中,当一个更改 model 的 view action 发生时,controller 不该该直接去操做 view 层级。正确的作法是,controller 去订阅 model 通知,而且在当通知到达时再更改 view 层级。这样一来,数据流就能够单向进行:view action 被转变为 model 变动,而后 model 发送通知,这个通知最后被转为 view 变动。”
  4. View State View state 能够按须要被 store 在 view 或者 controller 的属性中。相对于影响 model 的 view action,那些只影响 view 或 controller 状态的 action 则不须要经过 model 进行传递。对于 view state 的存储,能够结合使用 storyboard 和 UIStateRestoring 来进行实现,storyboard 负责记录活跃的 controller 层级,“而 UIStateRestoring 负责从 controller 和 view 中读取数据。”

MVVM

“MVVM 构建的方式和 MVC 的模式很类似:controller 层充分了解程序的结构,它使用这些认知来对全部部件进行构建和链接。 MVVM 与 MVC 最大的区别可能在于 view-model 中对响应式编程的使用了,它被用来描述一系列的转换和依赖关系。经过使用响应式编程来清晰地描述 model 对象与显示值之间的关系,为咱们从整体上理解应用中的依赖关系提供了重要的指导。 具体主要有三个不一样:翻译

  1. 必须建立 view-model。
  2. 必须创建起 view-model 和 view 之间的绑定。
  3. Model 由 view-model 拥有,而不是由 controller 所拥有。”

“MVVM 一般要求 controller 必须很是简单 (甚至简单到无需考虑)。另外,controller 必须尽量地使用库提供的绑定方法。在这样的规则的保证下,理想状况中咱们就不须要测试 controller 了,由于它没有包含咱们本身的任何逻辑。究竟应该在 controller 中留存多少逻辑,根本上来讲是掌握在程序员手上的。”

“MVVM 经过将 model 观察的代码以及其余显示和交互逻辑移动到围绕着数据流构建的隔离的类中,解决了 MVC controller 里不规则的状态交互所带来的有关问题。由于这是 MVC 中最显著的问题,并且会随着 Cocoa controller 的增大而恶化,这个变化在很大程度上缓解了 MVC 中 controller 肥大的问题。可是还有其余一些因素会使得 controller (以及 view-model) 变大,因此为了可持续发展,重构依然仍是有须要的”

MVVM.png

MVVM的构建

  1. 构建 和 MVC 不一样的是,view controller 再也不直接为每一个 view 获取和准备数据,它会把这项工做交给 view-model。View controller 在建立的时候会一并建立 view-model,而且将每一个 view 绑定到 view-model 所暴露出的相应属性上去。
  2. 更改 Model 在 MVVM 中,view controller 接收 view 事件的方式和 MVC 中同样 (在 view 和 view controller 之间创建链接的方式也相同)。不过,当一个 view 事件到达时,view controller 不会去改变自身的内部状态、view state、或者是 model。相对地,它当即调用 view-model 上的方法,再由 view-model 改变内部状态或者 model。
  3. 更改 View 和 MVC 不一样,view controller 不监听 model。View-model 将负责观察 model,并将 model 的通知转变为 view controller 能够理解的形式。View controller 订阅 view-model 的变动,这一般经过一个响应式编程框架来完成,但也可使用任意其余的观察机制。当一个 view-model 事件来到时,由 view controller 去更改 view 层级。 为了实现单向数据流,view-model 老是应该将变动 model 的 view action 发送给 model,而且仅仅在 model 变化实际发生以后再通知相关的观察者。
  4. View State View state 要么存在于 view 自身之中,要么存在于 view-model 里。和 MVC 不一样,view controller 中不存在任何 view state。View-model 中的 view state 的变动,会被 controller 观察到,不过 controller 没法区分 model 的通知和 view state 变动的通知。当使用协调器时,view controller 层级将由协调器进行管理。
  5. 测试 由于 view-model 和 view 层与 controller 层是解耦合的,因此可使用接口测试来测试 view-model,而不须要像 MVC 里那样使用集成测试。接口测试要比集成测试简单得多,由于不须要为它们创建完整的组件层次结构。 为了让接口测试尽量覆盖更多的范围,view controller 应当尽量简单,可是那些没有被移出 view controller 的部分仍然须要单独进行测试。在咱们的实现中,这部份内容包括与协调器的交互,以及初始时负责建立工做的代码。”

关于view-model

  • 实现状态恢复数据 在状态恢复的方法上,MVVM 中为各个 controller 所存储的数据来源于 view-model,而非像 MVC 那样来源于 controller 自己,除此以外,二者所使用的策略大抵相同。

  • View-model 虽然名字里既有 view 又有 model,可是它所扮演的实际上是彻彻底底的相似 controller 的角色。

  • View-model 从 view controller 和 view 中独立出来,也能够被单独测试。一样,view controller 也再也不拥有内部的 view state,这些状态也被移动到了 view-model 中。在 MVC 中 view controller 的双重角色 (既做为 view 层级的一部分,又负责协调 view 和 model 之间的交互),减小到了单一角色 (view controller 仅仅只是 view 层级的一部分)。

  • “View-model 在编译期间不包含对 view 或者 controller 的引用。它暴露出一系列属性,用来描述每一个 view 在显示时应有的值。把一系列变换运用到底层的 model 对象后,就能获得这些最终能够直接设置到 view 上的值。实际将这些值设置到 view 上的工做,则由预先创建的绑定来完成,绑定会保证当这些显示值发生变化时,把它设定到对应的 view 上去。响应式编程是用来表达这类声明和变换关系的很好的工具,因此它天生就适合 (虽然说不是严格必要) 被用来处理 view-model。在不少时候,整个 view-model 均可以用响应式编程绑定的方式,以声明式的形式进行表达。

  • “在理论上,由于 view-model 不包含对 view 层的引用,因此它是独立于 app 框架的,这让对于 view-model 的测试也能够独立于 app 框架。”

MVVM-C

“在理论上,由于 view-model 不包含对 view 层的引用,因此它是独立于 app 框架的,这让对于 view-model 的测试也能够独立于 app 框架。

因为 view-model 是和场景耦合的,咱们还须要一个可以在场景间切换时提供逻辑的对象。在 MVVM-C 中,这个对象叫作协调器 (coordinator)。协调器持有对 model 层的引用,而且了解 view controller 树的结构,这样,它可以为每一个场景的 view-model 提供所须要的 model 对象。”

和 MVC 不一样,MVVM-C 中的 view controller 历来都不会直接引用其余的 view controller (因此,也不会引用其余的 view-model)。View controller 经过 delegate 的机制,将 view action 的信息告诉协调器。协调器据此显示新的 view controller 并设置它们的 model 数据。换句话说,view controller 的层级是由协调器进行管理的,而不是由 view controller 来决定的。若是咱们忽略掉协调器,那么这张图表就很像 MVC 了,只不过在 view controller 和 model 之间加入了一个阶段。MVVM 将以前在 view controller 中的大部分工做转移到了 view-model 中,可是要注意,view-model 并不会在编译时拥有对 view controller 的引用。

“初步印象来讲,由于 MVVM-C 加入了额外的一层来进行管理,看起来是比 Cocoa MVC 模式更加复杂。不过,在实现的层级,若是你可以始终如一地贯彻这个模式,代码会变得更简单一些。啊,这里说的简单并不意味着容易,只有当你对常见的响应式代码变形熟悉之后,才不会对书写代码感到无从下手,才不会对调试问题感到懊恼沮丧。不过,从使人高兴的一面来讲,精心设计的数据管道一般不容易产生错误,在长期来看维护也更容易一些。”

MVVM-C.png

“iOS 中的协调器是一种颇有用的模式,由于管理 view controller 层级是一件很是重要的事情。协调器在本质上并无和 MVVM 绑定,它也能被使用在 MVC 或者其余模式上。”

协调器为每一个 controller 的 view-model 设置初始的 model 对象。 View-model 将设定值和其余 model 数据及观察量进行合并。 View-model 将数据变形为 view 所须要的精确的格式。 Controller 将准备好的值绑定到各个 view 上去。

MVP

对于Controller层过于臃肿的问题,MVP模式则能较好地解决这个问题——既然UIViewController和UIView是耦合的,索性把这二者都归为View层,业务逻辑则独立存在于Presenter层,Model层保持不变。下图比较清除得展现了MVP模式的结构

屏幕快照 2018-10-04 00.09.48.png

MVC-VS

MVC+VS.png

MAVB

“model 适配器 - view 绑定器 (ModelAdapter-ViewBinder, MAVB)”

MAVB.png

其余模式

Elm 架构 (TEA)、VIPER、Riblets

响应式编程

“响应式编程是一种用来交流变动的工具,不过和通知或者 KVO 不一样的是,它专一于在源和目标之间进行变形,让逻辑能够在部件之间传输信息的同时得以表达。” “响应式编程是一种用来描述数据源和数据消费端之间数据流动的模式” “数据变形的部分是响应式编程所能带来的最大优点,但同时它也是学习曲线最为陡峭的部分。”

相关文章
相关标签/搜索