在Swift中使用镜头进行嵌套依赖项修改

我个人喜欢KrzysztofZabłocki在他的文章中描述的模式。 这是一种简单的纯解决方案,它在层次结构中构建了依赖关系。 让我们来看一个例子:

想象一下这样一种情况,我们有提供用户年龄并具有Validator对象作为依赖项的UserProvider 。 在ViewModel某个地方,我们有一个反应性信号,通知用户年龄是否合适,例如:

现在,在测试中,我们有一个默认的验证实现,如果用户年满18岁,则返回true。 但是出于某种原因(例如测试),我们希望修改此验证以始终返回false ,这意味着由于年龄原因,可能不允许用户查看内容。 请注意, Validator对象嵌套在UserProvider中, UserProvider也嵌套在整个AppDependencies对象中。 这意味着我们必须编写很多代码,例如:

意味着您必须使每个struct属性var看起来很奇怪,因为我们不应该突变那些依赖结构。

现在想象一下, UserValidator比这三个闭包复杂得多,并且包含的​​内容更多。 这意味着很多样板代码,这当然是不需要的,尤其是在应该快速进行的测试中。

解? 镜片。

斯威夫特镜头是布兰登威廉姆斯推出的结构 您可以找到许多文章和视频来描述确切的镜头,但基本上,这些结构允许通过返回新实例来view并将某些特定属性set为不可变类型。 看到与UserValidator相同的修改,但是这次我们将使用镜头:

现在,我们保存与UserValidator执行的验证一样多的代码行。 但这是唯一的收获吗? 更改两个特定的(可能不同的)依赖项属性怎么样? 这就是镜头真正闪耀的地方!

请注意,我们修改了两个不同的属性,一个来自UserProvider ,另一个来自UserValidator. 这意味着您的应用程序中不再有任何样板代码,对于这些结构,您可以随意使用let而不是var🙂

但是等等,我错过了什么吗? 那些镜片在哪里?

我强烈建议您使用Sourcery工具(KrzysztofZabłocki的另一个工具)来自动生成镜头(并构造初始化器)。 您可以在Sourcery github存储库中找到模板。

通过将透镜与Sourcery结合使用,定义新的依赖关系并不重要,您只需要重新运行Sourcery脚本,一切都会自动更新。

这个故事与依赖注入的优缺点无关,但是它可能鼓励您在应用程序中使用此模式而不会受到伤害。 它使测试易于执行,并且确保快速进行。

从代码构造视图时,使用镜头也非常有用,但这是另一篇即将发表的文章的主题。

随时鼓掌! 😎