MVC-RS

RS字母在汽车工业中经常用来指代给定汽车的最强大版本。 对于MVC-RS,适用相同的想法:它是MVC,但是由于另外两个额外的层(路由器和存储),功能更加强大。

香草MVC

MVC的第一个版本是在70年代与SmallTalk一起推出的,旨在满足GUI应用程序不断增长的需求。 苹果公司推荐的用于构建应用程序的MVC新版本略有不同。 在此版本中,视图层和模型层不再相互了解。 完全分离这2个层的主要优点是使它们可重复使用。 但是,具有可重复使用的层意味着什么?

可重用性

Swift可以在所有Apple平台,iOS,macOS,watchOS和tvOS上重用,但也可以在Linux上以及某些天在Windows和android上重用。

重用View层与重用一些通用代码不同,因为View与它们所运行的平台紧密耦合。 这是有道理的,您没有呈现相同类型的UI,也不允许在手表,手机,平板电脑,计算机或电视上进行相同类型的用户交互。 如果您在macOS上编写了View层,则使用了AppKit,因此,只有在AppKit可用的情况下,该层才可以重用,这意味着只能在macOS上使用。

Model层没有View这样的约束,因此您应该能够在所有支持该语言的平台上重用Models。 您在iOS开发中经常遇到的第一个常见错误是在模型中使用UIKit。 Apple并没有为您提供帮助,因为他们在文档和某些WWDC会话中都犯了同样的错误。 这样做的问题是您不再可以在其他平台上重用Model。 让我们看一下这个例子:

在上面的示例中,您有3个不同的数据库提供程序。 如果您使用的是db A,则可以在任何地方重用Model。 但是,您可能还在macOS项目上使用了db C,并且该数据库在任何其他平台上均不可用。 在这种情况下,您的模型将无法在其他平台上重复使用。

这里的问题是,当您考虑MVC时,总是只考虑这三个层:模型,视图和控制器。 但实际上,有一个隐式的第四层:持久性(通常是本地文件,本地数据库或远程调用)。 如果您的模型知道您的持久性,则只有在您的持久性可用的情况下它才可以重用。 为避免这种情况,让我向您介绍MVC-RS的S层,它代表存储。

存储

存储层将只在您的持久性和模型之间进行,它将有2个任务:

  • 与持久性交谈
  • 将原始数据从“持久性”转换为模型的实体

与持久性交谈

此任务比看起来要复杂,因为对持久层的调用是异步的,因此它们可能会成功,但也可能会失败。 您的存储层将必须考虑所有这些参数。

转换数据

当您读取应用程序将呈现给用户的数据时,您的存储层会将从持久性获得的原始数据转换为模型的实体。 但是它也应该能够以其他方式做到这一点:当您的应用程序需要保留某些元素时,您的存储层应该知道如何将模型的实体转换为原始数据,并将其发送给Persistence。 重要的是要记住,这两个任务都可能失败。

在本文的示例中,您将看到之前的简单Car Model和非常方便且常见的Result枚举模式,而不是繁重的do-try-catch语法来管理错误。

这是您可能在存储层中找到的示例。

读取方法不会立即返回,因为对持久性的调用是异步的。 它们将闭包作为参数,当存储工作完成时将调用它。 如果在与Persistence交谈或将原始数据转换为Model实体时发生故障,则将调用onComplete闭包并显示错误,否则将使用适当的Model实体进行调用。

您可能会发现不同的读取方法,例如一种使用id来获取模型的单个实体的读取方法,或者另一种使用一些参数的读取方法,以防您不想加载模型的每个实例。

编写方法,创建,更新和删除完成了此CRUD示例。 它们具有相同的签名:它们采用Model的实体和onComplete闭包。 如果在将Model实体转换为原始数据或将该原始数据发送到Persistence时失败,则将调用onComplete闭包并显示错误。 否则,将以nil调用。

优点

将存储定义为协议非常方便,因为它允许您针对不同类型的持久性编写不同的实现。 您可能会发现一个用于sqlite数据库的数据库,另一个用于Couchbase数据库的数据库,一个用于某些Rest API调用的数据库……如果您要模拟持久性,还可以编写一个实现用于测试目的。

由于有了这个存储层,您的“模型”层现在仅可以对域进行建模。 它不再链接到您的持久层,因此可以在任何地方重复使用。 您的存储层以及模型都可以重用,但是只能在具有相同持久性的平台上使用。