在我正在研究的项目中,我有两个高度依赖于彼此的类:
@Singleton
class WorkExecutor {
@Inject Provider<ExecutionServices> services;
...
public void execute(Work w){
w.execute(services.get());
...
}
...
}
class ExecutionServicesImpl implements ExecutionServices {
@Inject WorkExecutor executor;
...
}
Run Code Online (Sandbox Code Playgroud)
这个想法是,在执行工作时,工作可以访问多个服务 - 其中一个是执行程序本身,这样工作就可以执行子工作.
可以看出,这里有一个循环依赖,但我发现很难打破.
主要问题是WorkExecutor在图形构建时实际上并不需要ExecutionServices对象的实例,而只需要稍后使用的提供程序.遗憾的是,Dagger不知道WorkExecutor不会从类的构造函数中调用ExecutionServices提供程序,因此它猜测ExecutionServices依赖于WorkExecutor,反之亦然.
我找到的一个可能的解决方案是以下列方式定义模块和组件:
interface DelayedProvider<T> extends Provider<T>{}
@Module
class AppModule {
Provider<ExecutionServices> delayedProvider = null;
@Provides DelayedProvider<ExecutionServices> provideDelayed() {
return () -> delayedProvider.get();
}
@Provides @Named("late-binding-conf") Void latebindingConf(Provider<ExecutionServices> eager){
this.delayedProvider = eager;
return null; //notice we returning Void and not void
}
}
@Component(modules=AppModule.class)
interface AppComponent {
App app();
@Named("late-binding-conf") Void configureLateBinding();
}
Run Code Online (Sandbox Code Playgroud)
然后我将原始类修改为:
@Singleton
class WorkExecutor {
@Inject DelayedProvider<ExecutionServices> services;
...
public void execute(Work w){
w.execute(services.get());
...
}
...
}
class ExecutionServicesImpl implements ExecutionServices {
@Inject WorkExecutor executor;
...
}
Run Code Online (Sandbox Code Playgroud)
然后为了创建我的应用程序,我必须做:
AppComponent acomp = DaggerAppComponent.create();
App = acomp.app();
acomp.configureLateBinding();
Run Code Online (Sandbox Code Playgroud)
但我不确定这是正确的行动方案 - 有更好的方法吗?
我不怀疑OP会喜欢这个,因为你想要一种方法让某些事情“错误”,工作“正确”。事实并非如此。每当遇到循环依赖项时,“正确”的解决方案是重构以删除该依赖项。
在您的情况下,WorkExecutor 是一个单例,因此它可能需要保持原样。然后应该修改 ExecutionServicesImpl 以删除对 WorkExecutor 的依赖。在不了解代码的具体情况的情况下,不能说太多。然而,让 ExecutionService 独立于它的“worker”可以减少耦合,从长远来看可能是一件非常好的事情。