MVC 编程最佳实践

编程入门 行业动态 更新时间:2024-10-10 05:16:26

<a href=https://www.elefans.com/category/jswz/34/1770109.html style=MVC 编程最佳实践"/>

MVC 编程最佳实践

什么是MVC

MVC 可能是世界上最著名的架构,它是一种设计模式,关注 App 的全局架构,并根据对象在 App 中的作用对其进行分类。MVC 由三个主要对象组成:

  • Model 模型:是数据所在的位置,像持久化、模型对象、解析器parser、管理器manager和网络请求代码这些东西都在这里。
  • View 视图:是 App 的 UI 界面,它们通常是可重用的,因为它们不包含任何业务逻辑。
  • Controller 控制器:通过委托 delegate 在视图和模型之间进行调解。在理想情况下,控制器不知道它正在处理的具体视图是什么。相反,它将通过协议的方式与抽象类进行通信。比如, UITableView 通过 UITableViewDataSource 协议与其数据源进行通信。

它们之间的协作看起来像这样:
这些对象中的每一种都通过抽象边界与其他对象分开,并跨越这些边界与其他类型的对象通信。

MVC 也是由几种更基本的设计模式组合而成的复合设计模式,这些基本模式共同定义了 MVC App 特有的功能分离和通信路径。

该复合设计模式中的控制器对象结合了中介模式策略模式,它负责传递模型和视图对象之间双向的数据流。模型状态的变化会通知控制器对象,视图对象则通过 target-action 机制来整合命令模式

Apple 的 MVC 文档中有详细说明,可以让我们在理论上有很好的理解。但从实用的角度来看,MVC 有点不足,容易产生 Massive View Controller。

我们在使用 MVC 时,只要没有太大的文件或难以扩展的代码,那么我们一样可以把 MVC 做的小而美,我们就能做得更好。

模型层(M)

模型对象封装数据和基本行为。它保存 App 的数据,并定义了操作该数据的逻辑。设计精良的 MVC App 将其所有重要数据封装在模型对象中,一旦数据加载到 App 中,任何属于 App 持久状态的数据(无论该持久状态存储在文件还是数据库中)都应驻留在模型对象中。由于它们代表了与特定问题领域相关的知识和专业知识,因此它们往往是可重复使用的。

通常下面这些代码应该被包含在这一层中:

  • 网络代码 Network code:最好只使用一个类在整个 App 中进行网络通信。它可以轻松抽象出所有网络请求通用的概念,例如 HTTP 标头、响应和错误处理等。
  • 持久化代码 Persistence code:将数据持久化到数据库、Core Data 或设备上。
  • 解析代码 Parsing code:在模型层中包含解析网络响应的对象。
  • 管理器和抽象层/类 Managers and abstraction layers/classes:每个人都使用它们,每个人都需要它们,没有人知道如何称呼它们或它们属于哪里。拥有典型的“manager”对象是很是正常的,这些对象通常充当其他类之间的粘合剂。这些也可以是较低级别、更强大的 API 的包装器:iOS 上的钥匙串包装器、差不多或帮助您使用 HealthKit 的模型。
  • 数据源和委托 Data sources and delegates:可能不太常见的是开发人员依赖模型对象作为其他组件(如表或集合视图)的数据源或委托。在控制器层中实现这些功能是很常见的,即使有很多最好保持分隔的自定义逻辑也是如此。
  • 常量 Constants:最好有一个包含常量的文件。考虑将它们放在结构或变量的结构中。这样,您就可以重用通知名称、date formatter、颜色等。
    助手和扩展 Helpers and extensions:我们经常会添加方法来扩展字符串、集合等的功能,这些也可以被视为模型层的一部分。

模型对象可以与其它模型对象具有 1:M 和 M:M 关系,它不应该直接与视图对象通信,也不应该关心用户界面。

我们不应该把注意力放在项目中是否有 Model 文件目录上,也不需要关注 Model 文件夹中存放的是否都是 dataModel,我们的目标是在只要符合模型对象的代码都应该放到 Model 中。

通信

  • 当 View 层发生某些事情时,例如当用户启动一个动作时,它会通过 Controller 传递给 Model。
  • 当模型发生变化时,例如当有新数据可用时,模型会通知控制器。

视图层(V)

视图对象知道如何显示 App 模型对象中的数据,并可能允许用户编辑数据,但它不负责存储正在显示的数据。视图对象可以只负责显示模型对象的一部分,或整个模型对象,甚至许多不同的模型对象。

视图对象往往是可重用和可配置的,它们提供了 App 之间的一致性。

视图的目的是显示来自模型的数据并使其可用于用户交互,它不应包含与 UI 无关的任何内容,这包括网络调用、业务逻辑、操作模型等。通常这些代码被包含在这一层中:

  • UIView 子类:从基本的 UIView 到复杂的自定义 UI 控件。
  • UIKit/AppKit 中的类
  • Core Animation 核心动画
  • Core Graphics 绘图

检查视图层是否合理时,可以使用以下内容作为清单:

  • 它是否与模型层交互?
  • 它包含任何业务逻辑吗?
  • 它会尝试做任何与 UI 无关的事情吗?

如果这些问题中的任何一个回答为“是”,就需要进行视图对象清理重构。

视图应确保它正确地显示模型。因此,它通常需要知道模型的变化。由于模型对象不应绑定到特定的视图对象,因此它们需要一种通用的方式来指示变更,比如使用中介控制器。

最后,衡量一个编写良好的视图组件的标准通常是可重用的,但不要从一开始就关注这一点,仅在实际需要时才去做重用性设计。当这个组件有多个使用场景时,就是让组件更通用的时候了。

通信
视图不能直接与模型通信,一切都通过控制器完成。

控制器层(C)

控制器对象是 App 中可重用性最低的部分,因为它通常涉及特定领域的规则。控制器对象是 MVC 的核心层,充当 App 视图对象与其模型对象之间的中介,通常负责确保视图可以访问它们需要显示的模型对象,并充当视图了解模型更改的管道。控制器对象还可以为 App 执行设置和协调任务,并管理其他对象的生命周期。

通常,这一层做的事情如下:

  • 初始化视图对象并布局
  • 加载数据:从持久化存储或者网络
  • 协调 Model 与 View,配置展示数据,刷新界面
  • 处理用户交互,更新模型or发起网络请求
  • 管理视图生命周期
  • 。。。

将控制器层视为 App 的大脑或引擎;它决定接下来会发生什么。在大多数情况下,它意味着触发数据加载、处理 UI 交互、在 UI 和模型之间进行调解等。

在典型的 Cocoa MVC 设计中,当用户通过视图对象输入值或指示选择时,该值或选择会传达给控制器对象。控制器对象可能会以某种特定于 App 的方式解释用户输入,然后告诉模型对象如何处理此输入。基于相同的用户输入,一些控制器对象也可能告诉视图对象更改其外观或行为的一个方面,例如告诉按钮禁用自己。相反,当模型对象发生变化(例如访问新的数据源)时,模型对象通常会将该更改传达给控制器对象,然后控制器对象请求一个或多个视图对象相应地更新自己。

控制器对象可以是可重用的,也可以是不可重用的,具体取决于它们的一般类型。在 Cocoa 中有两种通用的控制器对象:中介控制器 Mediator和协调控制器 Coordinate。每种类型的控制器对象都与一组不同的类相关联,每种类都提供不同的行为范围。

组合角色

我们可以合并对象扮演的 MVC 角色。例如,使对象同时履行控制器和视图角色——在这种情况下,它将被称为视图控制器。同样,我们也可以拥有模型控制器对象。对于某些 App,组合这样的角色是一种可接受的设计。

模型控制器是主要关注模型层的控制器,它“拥有”模型,它的主要职责是管理模型并与视图对象通信,适用于整个模型的操作方法通常在模型控制器中实现。

视图控制器是一种主要关注视图层的控制器,它“拥有”界面(视图),它的主要职责是管理界面并与模型通信,与视图中显示的数据相关的操作方法通常在视图控制器中实现。

通信

  • 可以与模型和视图这两个层进行通信。
  • 控制器解释用户操作并通过模型层触发对数据的更改。
  • 当数据发生变化时,它确保将这些变化传达给用户界面,更新视图

何时使用 MVC

在我们的项目中,初始的架构模式就是 MVC,当我们不准备使用其它架构模式时,可以根据以下评判标准来判断是否要使用 MVC

  • 模块所涉及的业务非常简单,仅需要处理集合数据展示,没有复杂的视图
  • 模块相对稳定,后期迭代频率非常低,业务复杂度一般或较低
  • 本地数据展示的模块,不涉及网络交互

MVC 代码组织

Model 层:

  • xxAPI —— 网络请求接口封装类,负责网络请求发出与响应、数据解析,接口回调中建议交付解析好的 dataModel 给业务调用方使用。
  • xxManager —— 强业务逻辑类,负责处理强业务相关的功能逻辑封装,记录状态
  • xxStore —— 数据存储类(内存 & 磁盘,包含 db),负责数据缓存和持久化,提供操作数据的接口。
  • 其它类(如 helper) —— 弱业务逻辑类,负责处理弱业务相关的功能逻辑封装。

View 层:

  • 具体 UI 视图的定制封装,通过 3 种方式向外提供数据展示能力:
    • 1、通过 protocol 为视图提供特定的数据源协议以配置视图;
    • 2、通过在头文件中对外暴露需要赋值的只读属性来配置视图(注意:只暴露需要赋值的属性);
    • 3、提供 setter 方法为 UI 元素赋值提供接口,也可以把这些 setter 方法做成一个配置类。
  • 布局的初始化与更新
  • 动画
  • 用户交互,通过委托 delegate 或 block 的方式向外传递事件
  • 绘制,一些 UI 特效的绘制,如圆角、边框、阴影、Core Graphics 等
  • 其它 UIKit 下的定制类

Controller 层:

  • 在我们的 App 中,这一层通常放的是视图控制器,管理视图的生命周期,用来协调某个具体界面所定制的 View 上能够展示对应的数据 Model,并处理用户交互
  • 业务上应该都是一些调用入口点,负责发起业务并处理回调,具体的业务逻辑应该封装在 Model 层
  • 在组织代码时,应该按照 Timetable 演示模块所示范的形式来组织代码,通过 pragma mark - 标记来为控制器的代码梳理分类,以防止一些不必要写在控制器的代码侵蚀导致产生 Massive View Controller,也便于代码的统一维护
  • 通常有这些板块:#pragma mark - view life cycle、#pragma mark - UI initialize、#pragma mark - 数据加载与处理、#pragma mark - notifications、#pragma mark - kvo methods、#pragma mark - timer、#pragma mark - actions、#pragma mark - 各类协议依次排开(如 UITableViewDataSource、UITableViewDelegate 等)、#pragma mark - 埋点、#pragma mark - setters & getters

参考链接

模型视图控制器 (MVC) — GitHub Repo 链接和文章链接
模型视图 ViewModel (MVVM) — GitHub Repo 链接和文章链接
Model View Presenter (MVP) — GitHub Repo 链接和文章链接
协调器模式 — MVP with Coordinators (MVP-C) — GitHub Repo 链接和文章链接
查看 Interactor Presenter Entity Router (VIPER) — GitHub Repo 链接和文章链接
查看 Interactor Presenter (VIP) — GitHub Repo 链接和文章链接

更多推荐

MVC 编程最佳实践

本文发布于:2024-02-14 09:17:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762938.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:MVC

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!