iOS*_*eek 8 dependency-injection inversion-of-control factory-pattern ios swift
我们如何在不使用框架的情况下应用依赖注入,当我们有两个层次结构非常深的UIViewController并且它们都需要相同的依赖关系来保存状态时,那两个UIViewControllers它们没有共同的父代.
例:
VC1 - > VC2 - > VC3 - > VC4
VC5 - > VC6 - > VC7 - > VC8
让我们看看他们都需要VC4和VC8 UserService来保存当前用户.
请注意,我们要避免使用Singleton.
是否有一种优雅的方式来处理这种DI情况?
经过一番研究,我发现,有些提Abstract Factory,Context interfaces,Builder,strategy pattern
但我找不到如何在iOS上应用它的示例
好的,我会试一试.
你说"没有单身人士",所以我在下面排除了这一点,但也请看这个答案的底部.
Josh Homann的评论已经成为一个解决方案的好指针,但我个人对协调器模式有疑问.
正如Josh正确地说视图控制器不应该(很多)知道彼此[1],但那么如何协调器或任何依赖传递/访问?有几种模式可以提示如何,但是大多数都有一个基本上违背你的要求的问题:它们或多或少地使协调者成为一个单身人士(或者自己或者作为另一个单身人士的财产AppDelegate).协调员通常也会成为一个单身因子(但并非总是如此,而且并非必须如此).
我倾向于做的是依赖于简单的初始化属性或(最常见的)惰性属性和面向协议的编程.让我们构建一个示例:UserService应该是定义服务所需的所有功能的协议,MyUserService它的实现结构.假设UserService是一种设计构造,其基本上用作一些用户相关数据的getter/setter系统:访问令牌(例如保存在钥匙串中),一些偏好(化身图像的URL)等.初始化时MyUserService也会准备数据(例如,来自远程的负载).这将用于几个独立的屏幕/视图控制器,而不是单例.
现在,每个对访问此数据感兴趣的视图控制器都具有以下简单属性:
lazy var userService: UserService = MyUserService()
Run Code Online (Sandbox Code Playgroud)
我保持公开是因为这允许我在单元测试中轻松地模拟/存根(如果我需要这样做,我可以创建一个模拟TestUserService/存根行为的模拟).实例化也可以是一个闭包,如果init需要参数,我可以在测试期间轻松切换出来.显然,属性甚至不一定需要lazy取决于对象实际执行的操作.如果提前实例化对象没有任何损害(记住单元测试,还有传出连接),只需跳过lazy.
诀窍显然是设计UserService和/或MyUserService以一种在创建它的多个实例时不会导致问题的方式.但是,我发现90%的时间这不是真正的问题,只要实例应该依赖的实际数据保存在其他地方,在单一的事实中,如钥匙串,核心数据堆栈,用户默认值或远程后端.
我知道这是一种解决问题的答案,因为在某种程度上我只是说描述了一种方法(至少是其中的一部分).但是我发现这是在Swift中处理依赖注入的最通用和最简单的形式.协调器模式可以与它正交使用,但我发现它在日常使用中不那么"像苹果一样".它确实解决了一个问题,但主要是你得到的问题,你没有正确使用故事板(特别是:只是将它们用作"VC repos",从那里实例化并在代码中转换自己).
[1]除了一些基本和/或次要的东西,你可以通过完成处理程序或prepareForSegue.这是有争议的,取决于你遵循协调员或其他模式的严格程度.就个人而言,我有时会在这里采取捷径,只要它不会膨胀并且变得混乱.一些弹出式设计更简单.
作为结束语,"请注意我们要避免使用Singleton"这一短语以及您对该问题的评论给我的印象是,您只是在没有充分考虑其基本原理的情况下遵循该建议.我知道"单身人士"经常被认为是一种反模式,但正如判断错误通知一样.单例可以是一个有效的架构概念(您可以通过它在框架和库中广泛使用的事实来看到).关于它的坏处只是它经常诱使开发人员在设计中采用快捷方式并将其作为"对象存储库"滥用,这样他们就不需要考虑实例化对象的时间和地点.这导致了混乱和模式的坏名声.
答UserService:取决于你的应用程序实际上做了什么可能是单身人士的一个很好的候选人.我个人的经验法则是:"如果它管理一些单一且独特的东西的状态,就像在特定时间只能处于一种状态的特定用户",我可能会选择一个单身人士.
特别是如果你不能按照我上面概述的方式设计它,即如果你需要内存中的单数状态数据,单例基本上是一种简单而正确的方法来实现它.(即使然后使用(懒惰)属性也是有益的,您的视图控制器甚至不需要知道它是否是单例,并且您仍然可以单独存根/模拟它(即不仅仅是全局实例).)
| 归档时间: |
|
| 查看次数: |
573 次 |
| 最近记录: |