因此,我有一些运行算法的代码,例如使用AlgoRunner类。现在,可以使用多种方式实现此AlgoRunner类,以使用Algo类运行不同的算法。我想使用Dagger 2向“管理器”类提供AlgoRunner类的不同实现,该类将输入传递给AlgoRunner及其管理的其他组件。



我现在有以下内容,但是我不确定这是否正确,主要是因为该AlgoRunnerProvider模块为空。还有其他方法可以实现我想要做的事情吗?还是简化我所拥有的?

我是否应该只创建一个不同的组件OneAlgoRunnerComponent和TwoAlgoRunnerComponent并从每个组件中注入Manager?

构造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;
    }
}


覆盖AlgoRunnerProvider中的Provides方法的OneAlgoRunnerProvider。
也可以有一个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);


非常感谢!

最佳答案

匕首框架用于为您处理对象创建。如果您要在要提供的一个类中进行某种初始化,则可能有些不符合预期的情况(请参见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();
    }
}




可能还有更多的可能性,尤其是开始混合使用这些方法时,但我认为这3是您可以使用的基本工具。

07-24 19:05
查看更多