Ios 您如何处理应用程序中的共享对象(服务定位器和/或依赖项注入)?

Ios 您如何处理应用程序中的共享对象(服务定位器和/或依赖项注入)?,ios,objective-c,dependency-injection,singleton,service-locator,Ios,Objective C,Dependency Injection,Singleton,Service Locator,您如何处理通过应用程序服务定位器和/或DI共享的组件 每个应用程序都有我们反复遇到的通用组件。这些可能是DatabaseManager、CacheManager、UserManager、ReportingManager、SettingsManager、BackendAPIManager、CrashManager等等 在我的例子中,这些组件通常是类,因为我喜欢将相关的东西封装到组件中,这些组件提供了对代码其他部分的良好和简单的访问。作为一般的经验法则,我们可以将代码封装到一个类中,只要该类按照单一

您如何处理通过应用程序服务定位器和/或DI共享的组件

每个应用程序都有我们反复遇到的通用组件。这些可能是DatabaseManager、CacheManager、UserManager、ReportingManager、SettingsManager、BackendAPIManager、CrashManager等等

在我的例子中,这些组件通常是类,因为我喜欢将相关的东西封装到组件中,这些组件提供了对代码其他部分的良好和简单的访问。作为一般的经验法则,我们可以将代码封装到一个类中,只要该类按照单一的可响应性原则运行,并且不会太大

其中一些类类似于第三方库的包装器—ReportingManager、CrashManager Google Analytics、Crashlytics等,一些类封装了web服务,调用part—AFNetworking的BackendAPIManager。有些还类似于包装器—DatabaseManager核心数据、FMDB、CacheManager序列化为文件设置Manager NSUserDefault

提到的大多数组件/类都不存储状态或其他任何东西——它们的实现只是封装了行为代码。但是,有些类封装了行为代码和状态代码,例如UserManager与BackendAPIManager交互,存储检索到的用户,存储登录状态,并具有很好的API方法:login、logout、register、resetPassword、isLoggedIn

现在,有一个很高的诱惑来创建单例,但我们都知道单例不利于单元测试。因此,一种可能的方法是使用registerObject、getObject方法创建一种单例注册表(也称为服务定位器设计模式),并在应用程序启动期间创建和注册所有这些对象,然后始终通过以下方式使用:

[[Registry shared] getObject:@protocol(UserManagerProtocol)];
因此,在测试中,您可以注销不需要的管理器,并通过Registry registerObject注册模拟。服务定位器模式由他描述,根据他的说法,它是依赖注入的替代方案。然而,另一位来自.NET world的杰出作者声称服务定位器是一种反模式,主要是因为您不需要忘记注册新的共享对象,需要知道应用程序是如何工作的,因为注册表隐藏了所有依赖项,开发人员不喜欢为单元测试重置和注册这些共享对象

虽然服务定位器和依赖项注入都有助于将依赖对象从使用代码中分离出来,但依赖项注入在各种讨论和论坛中更受欢迎,而且看起来更受欢迎。虽然我以前在共享组件中使用服务定位器,有时在代码中注入非共享对象时使用DI,但我对处理共享对象的替代方法很感兴趣。一些migh建议不关心对象的单一性,只需创建新实例并每次使用依赖项注入进行注入,但复制这些对象的方法不好,如果对象存储状态,有时会导致问题

我正在使用和扩展BaseModel、BaseViewController,因此我很容易在这两个类上添加相关的管理器属性以进行依赖项注入。I'v used属性,默认值类型为DI实现:

这样,我就不需要一次又一次地将依赖项显式地传递给BaseModel和BaseViewController的子类。默认值将从注册表中获取。所有共享对象都将在app launch ServiceLocator上注册:

[[Registry shared] register:[UserManager new]];
[[Registry shared] register:[SettingsManager new]];
[[Registry shared] register:[BackendAPIManager new]];
...
然后在其他代码中使用self.userManager、self.setingsmanager、self.backendapimager来访问它们

因此,建议的解决方案使用依赖项注入+服务定位器,通过我们公开并添加到BaseModel和BaseViewController@userManager、@SettingsManager、@backendAPIManager的属性,编写单元测试并显式注入和设置依赖项非常容易

你认为这种方法怎么样?我只是试图避免使用DI框架,因为我总是试图保持代码干净,易于调试

相关:
[[Registry shared] register:[UserManager new]];
[[Registry shared] register:[SettingsManager new]];
[[Registry shared] register:[BackendAPIManager new]];
...