我考虑将一些图书馆迁移到Dagger 2。该库公开了一个可配置的客户端,每个配置都可以命名,然后以单一方式检索。
让我从用户的角度展示一个关于库如何工作的伪代码:
// initialization
ClientSDK clientA = new ClientSDK.Builder()
.configuration().attributes().here()
.apiKey("someString") // set api key / credentials
.build();
LibraryAuthenticationManager customAuthManager = new MyCustomAuthenticationManager();
ClientSDK clientB = new ClientSDK.Builder()
.configuration().attributes().here()
.apiKey("someStringElse")
.customAuthManager(customAuthManager) // override some default
.baseApiUrl("https://custom.domain.com/and/path") // override some default setting
.build();
ClientSDK.setSingleton("clientA", clientA);
ClientSDK.setSingleton("clientB", clientB);
当我需要其他地方的实例时:
// usage everywhere else
ClientSDK clientB = ClientSDK.singleton("clientB");
clientB.userManager(); // "singleton" using the configuration of clientB
clientB.subscriptionsManager(); // "singleton" using the configuration of clientB
clientB.currentCachedUser(); // for clientB
clientB.doSomething(); // action on this instance of the ClientSDK
ClientSDK
实例由库的用户创建,ClientSDK静态保存与名称关联的单例映射。
(SDK的实际行为略有不同:命名是自动的,基于强制配置参数。)
就像我有很多单一类具有单一入口点(ClientSDK),但由于我可以使用自己的单例实例对ClientSDK进行多次配置,因此这不是真正的单例。
如果我尝试使用Dagger 2编写类似的库,我会做类似的事情:
class ClientSDK {
@Inject SDKConfiguration configuration;
@Inject LibraryAuthenticationManager authManager;
...
}
问题是我需要ClientSDK的每个实例都有自己的配置和authManager(以及许多其他服务)注入。它们需要从库用户可以定义(配置)和可覆盖(实际实现)。
我可以用Dagger 2做这样的事吗?怎么样?
我已经看到我可以创建自定义范围,但它们是在编译时定义的,库用户应该是定义它们的那个。
(该库是一个Android库,但这不应该是相关的)
由于
答案 0 :(得分:1)
听起来你应该创建有状态/可配置的模块实例,然后为你构建的每个ClientSDK生成单独的组件或子组件。
public class ClientSDK {
@Inject SDKConfiguration configuration;
@Inject LibraryAuthenticationManager authManager;
// ...
public static class Builder {
// ...
public ClientSDK build() {
return DaggerClientSDKComponent.builder()
.configurationModule(new ConfigurationModule(
apiKey, customAuthManager, baseApiUrl)
.build()
.getClientSdk();
}
}
}
...您编写的ConfigurationModule是@Module
,其中包含所有这些配置参数并通过适当的@Provides
方法访问它们,您的ClientSDKComponent是@Component
你定义引用ConfigurationModule(以及其他)并定义@Component.Builder
内部接口。 Builder很重要,因为你告诉Dagger它不能再静态地使用它的模块,或者通过它自己创建的实例:你必须调用一个构造函数或以其他方式获取一个实例,然后Component可以使用它来提供实例。
Dagger不会涉及保存您的命名单例,但它不需要:您可以将它们自己保存在静态Map中,或者将ClientSDKComponent实例保存为入口点。就此而言,如果您放心使用ClientSDK的某些控件,您甚至可以将ClientSDK本身作为Component;但是,我建议反对它,因为你对所需的静态方法的控制较少,并且将失去编写任意方法或根据需要抛出异常的机会。
您不必担心范围,除非您想:Dagger 2通过组件实例生命周期跟踪范围生命周期,因此为了清晰起见,范围很容易添加,但如果您对“无范围的“物体。如果您有一个真正的单例对象的对象图,您还可以将该组件存储为常规(静态最终字段)单例,并将该ClientSDKComponent生成为该较长寿命组件的subcomponent。如果它对您的构建依赖关系图很重要,您也可以用另一种方式对其进行短语,并将您的ClientSDKComponent作为独立组件依赖于另一个@Component
。