作者:安静的美男只 | 来源:互联网 | 2023-02-05 21:48
我是Dagger 2的新手,我正在寻找一种具有“可配置组件”的方法。
本质上,这就是我想要实现的目标:
public interface ErrorReporter{
...
}
public class ConsoleErrorReporter implements ErrorReporter{
... // Print to System.err
}
public class DialogErrorReporter implements ErrorReporter{
... // Show modal dialog to user
}
@Module
public interface UIModule{
@Provides
ErrorReporter provideErrorReporter();
}
@Module
public class ConsoleUIModule{
@Override
@Provides
ErrorReporter provideErrorReporter(ConsoleErrorReporter cer){
return cer;
}
}
@Module
public class GraphicalUIModule{
@Override
@Provides
ErrorReporter provideErrorReporter(DialogErrorReporter der){
return der;
}
}
@Component(modules = {UIModule.class, OtherUniversalModule.class})
public interface ApplicationComponent{
ErrorReporter errorReporter();
}
void main(String[] args){
final UIModule uiModule;
if(args.length == 1 && args[0].equals("gui")){
uiModule = new GraphicalUIModule();
}else{
uiModule = new ConsoleUIModule();
}
DaggerApplicatiOnComponentdac= DaggerApplicationComponent.builder()
.uiModule(uiModule).build();
dac.errorReporter().showError("Hello world!");
}
@Provides methods cannot be abstract
不幸的是,以上操作均因接口和抽象类而失败。我还尝试了非抽象基类的具体实现,这些实现返回null,然后在子类中覆盖它们。但是,这也失败了@Provides methods may not override another method
。
简而言之,我想为模块定义合同,并在运行时选择不同的模块。我知道Dagger 2的编译时间可以验证对象图,但是如果我有一个定义明确的合同,那仍然应该可行吗?还是我被迫使用两个用户界面的重复代码创建两个不同的组件?我还缺少其他解决方案吗?
1> David Medenj..:
我认为以这种方式使用模块是不可能的,因为...
假设您的类具有以下两个构造函数
@Inject ConsoleErrorReporter(Console console);
@Inject DialogErrorReporter(Graphics graphics);
这意味着ConsoleUIModule
将需要一个Console
和DialogErrorReporter
一个Graphics
对象来创建其各自的实现。ErrorReporter
。
但是如果匕首只知道 UIModule
因为您在那儿使用了接口……那么……它不能提供任何依赖,因为它不知道其中的任何一个。
而且,如果您不知道在编译时建立依赖关系图的依赖关系将无法工作。而且即使没有匕首也不会编译,因为provideErrorReporter(ConsoleErrorReporter cer)
不会覆盖provideErrorReporter()
。
您可以并且应该做的是使用不同的组件。因为组件是真正知道如何提供东西的东西。组件已经是接口了,这就是您想要的,对吧?
您可以具有组件依赖关系,其中一个组件依赖于另一个。例如DependentComponent
,提供的NeedsErrorReporter
,需要实现ErrorReporter
。我们还依赖于接口,而不是实际的组件(毕竟,这就是您想要的,对吧?)
然后,您可以通过实际的组件来实现该接口,并且每个组件都有其各自的模块(甚至可能还有其他依赖性)。最后,您将拥有一个可以切换的组件,并将提供正确封装的对象的不同版本!
@Component(dependencies = UIComponent.class) /* <- an interface! */
interface DependentComponent {
NeedsErrorReporter needsErrorReporter();
}
class NeedsErrorReporter {
@Inject public NeedsErrorReporter(ErrorReporter reporter) { }
}
/* this is _not_ a component, but a simple interface! */
interface UIComponent {
ErrorReporter errorReporter();
}
/* Console */
@Component(modules = ConsoleUIModule.class)
interface ConsoleUIComponent extends UIComponent { }
@Module interface ConsoleUIModule {
@Binds ErrorReporter provideErrorReporter(ConsoleErrorReporter cer);
}
/* Graphic */
@Component(modules = GraphicalUIModule.class)
interface GraphicUIComponent extends UIComponent { }
@Module interface GraphicalUIModule {
@Binds ErrorReporter provideErrorReporter(DialogErrorReporter der);
}
/* The error reporter variants */
interface ErrorReporter {
}
class ConsoleErrorReporter implements ErrorReporter {
@Inject public ConsoleErrorReporter() { }
}
class DialogErrorReporter implements ErrorReporter {
@Inject public DialogErrorReporter() { }
}
现在您所要做的就是选择正确的组件;)
DaggerDependentComponent.builder().uIComponent(DaggerConsoleUIComponent.create()).build();
// or
DaggerDependentComponent.builder().uIComponent(DaggerGraphicUIComponent.create()).build();