带有Dagger 2的可交换模块

时间:2016-02-26 17:51:50

标签: java android dagger-2

所以我有一些运行算法的代码,比如使用AlgoRunner类。现在,这个AlgoRunner类可以通过多种方式实现,以使用Algo类运行不同的算法。我想使用Dagger 2将AlgoRunner类的不同实现提供给" Manager"将输入传递给AlgoRunner以及它管理的其他组件的类。

问题

我现在有以下内容,但我不确定这是否正确,主要是因为空的AlgoRunnerProvider模块。是否有其他方式来实现我想要做的事情?或者为了简化我的工作?

我是否应该创建不同的组件OneAlgoRunnerComponent和TwoAlgoRunnerComponent并从每个组件中注入管理器?

构造Manager实例的类使用此组件将AlgoRunner注入到该实例中,以便Manager可以将输入传递给它。

@Component(
        modules = {
                AlgoRunnerProvider.class
        }
)
public interface AlgoRunnerComponent {
    void inject(Manager manager);
    AlgoRunner getAlgoRunner();
}

AlgoRunnerProvider模块

@Module
public class AlgoRunnerProvider {

    @Provides
    public AlgoRunner getAlgoRunner() {
        return null;
    }
}

OneAlgoRunnerProvider,它覆盖AlgoRunnerProvider中的provide方法。 也可以有一个TwoAlgoRunnerProvider,它可以做同样的事情并提供TwoAlgoRunner,只要它扩展了AlgoRunner。

public class OneAlgoRunnerProvider extends AlgoRunnerProvider {
    private final OneAlgo algo;

    public OneAlgoRunnerProvider(OneAlgo algo) {
        this.algo = algo;
    }

    @Override
    public OneAlgoRunner getAlgoRunner() {
        return new OneAlgoRunner(algo);
    }
}

现在所有这些都是这样使用的:

AlgoRunnerComponent build = DaggerAlgoRunnerComponent.builder()
                .algoRunnerProvider(new OneAlgoRunnerProvider(new OneAlgo()))
//              .algoRunnerProvider(new TwoAlgoRunnerProvider(new TwoAlgo()))
                .build();

        Manager manager = managerComponent.getManager();
        build.inject(manager);

        Truth.assertThat(manager.algoRunner).isInstanceOf(OneAlgoRunner.class);
//      Truth.assertThat(manager.algoRunner).isInstanceOf(OneAlgoRunner.class);

非常感谢!

1 个答案:

答案 0 :(得分:3)

匕首框架用于为您处理对象创建。如果你开始在你希望提供的一个类中进行某种初始化,那么可能会有一些不应该的东西(参见getAlgoRunner())。

如果您希望在运行时提供不同类型,则需要某些工厂来创建正确的对象。输入匕首。

您有多种方法可以实现您的目标。基本上,模块应该处理对象创建:

@Module
public class AlgoRunnerProvider {

    @Provides
    public AlgoRunner getAlgoRunner() {
        // todo create the correct type
        return null;
    }
}

1。 @Named注释(或其他Qualifier

如果你知道编译时哪个类需要哪种类型,你应该使用限定符。

@Named("Version1")
@Inject
AlgoRunner mRunner;

然后,您可以从模块中提供不同的实现:

@Provides
@Named("Version1")
public AlgoRunner getAlgoRunner() {
    return new Version1AlgoRunner();
}

@Provides
@Named("OtherVersion")
public AlgoRunner getAlgoRunner(Depends someOtherDependency) {
    return new OtherVersionAlgoRunner(someOtherDependency);
}

2。在运行时切换

虽然您总是可以通过创建具有不同依赖关系的多个类来使用第一个选项,但您可能希望能够在运行时选择。为此,您需要将一些参数传递给您的模块:

@Module
public class AlgoRunnerProvider {

    private final int mType;

    public AlgoRunnerProvider(int type) {
        mType = type;
    }

    @Provides
    public AlgoRunner getAlgoRunner() {
        if(mType == TYPE_A) {
            return new Version1AlgoRunner();
        } else {
            return new OtherVersionAlgoRunner();
        }
    }
}

使用此变体,您仍然可以在模块中使用创建逻辑,其中包含依赖项。

3。使用不同的模块

另一种方法是使用不同的模块。如果在编译时确定(使用不同模块的不同类)而不是在运行时在同一类中选择逻辑,那么这只是一个干净的解决方案。

如果您开始编写像if typeA then moduleA else moduleB这样的代码,您应该停下来做其他事情。

您可以使用相同的组件,但通过使用良好的旧继承,使用不同的模块为不同的类创建它。每个模块只提供AlgoRunner的实现。

// one class using one module to get a specific behavior
public class MyClassVersionA {

    public void onCreate(Bundle saved) {
        component.myModule(new MyModuleVersionA()).build();
    }
}

// another class using a different module to get a different behavior
public class MyClassSomethingElse {

    public void onCreate(Bundle saved) {
        component.myModule(new MyModuleSomethingElse()).build();
    }
}

然后你就可以相应地对你的模块进行子类化

// did not test the following, something like this...
public abstract class MyModule {

    @Provides
    public AlgoRunner getAlgoRunner();

}

public class MyModuleVersionA extends MyModule {

    @Provides
    @Override
    public AlgoRunner getAlgoRunner() {
        return new Version1AlgoRunner();
    }
}
public class MyModuleSomethingElse extends MyModule {

    @Provides
    @Override
    public AlgoRunner getAlgoRunner() {
        return new SomeOtherAlgoRunner();
    }
}

可能还有更多的可能性,特别是如果开始混合这些方法,但我认为这些是你可以使用的基本工具。