Emi*_* L. 3 java interface inversion-of-control dagger-2
我是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的编译时间可以验证对象图,但是如果我有一个定义明确的合同,那仍然应该可行吗?还是我被迫使用两个用户界面的重复代码创建两个不同的组件?我还缺少其他解决方案吗?
我认为以这种方式使用模块是不可能的,因为...
假设您的类具有以下两个构造函数
@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();
| 归档时间: | 
 | 
| 查看次数: | 1049 次 | 
| 最近记录: |