如何告诉Dagger 2基于X实例化哪个实现? [英] How do I tell Dagger 2 which implementation to instantiate based on X?

查看:90
本文介绍了如何告诉Dagger 2基于X实例化哪个实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在模块内部,如果我需要根据模块构造时已知的变量提供不同的接口实现,我可以将逻辑放在@Provides方法中用于该接口类型。像这样:

Inside a module, if I need to provide a different implementation of an interface based on a variable known at module construction time I can put the logic inside the @Provides method for that interface type. Like so:

@Module
public class FooModule {

    private final State state;

    public FooModule(State state) {
        this.state = state;
    }

    @Provides
    FooInterface provideFooImplementation() {
        switch(state) {
            case STATE_1:
                return new FooImpl1();
            case STATE_2:
                return new FooImpl2();
            ...
            case STATE_10:
                return new FooImpl10();
        }
    }
}

但是,这些实现可能是由Dagger创建。我宁愿说嘿,基于XI希望你为我实例化这个课程

However, these implementations could be created by Dagger. I would rather say "Hey, based on X I want you to instantiate this class for me"

我考虑了几个选项。


  1. 更改提供方法以接受所有可能的实施:

  1. Change the provides method to take in all of the possible implementations:

@Provides
FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) {
    switch(state) {
        case STATE_1:
            return impl1;
        case STATE_2:
            return impl2;
        ...
        case STATE_10:
            return impl10;
    }
}


这允许Dagger实例化它们并满足它们的所有依赖关系,但是如果每个实现都相对较大或者创建起来很昂贵,那么这不是一个好主意。

This allows Dagger to instantiate them and satisfy all of their dependencies but it's not a good idea if each of the implementations is relatively large or expensive to create.


  1. 更改提供方法以接收不同实现的所有依赖关系的集合。

  1. Change the provides method to take in a collection of all of the dependencies for the different implementations.

@Provides
FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) {
    switch(state) {
        case STATE_1:
            return new FooImpl1(context);
        case STATE_2:
            return new FooImpl2(repo, httpClient);
        ...
        case STATE_10:
            return new FooImpl10(context, repo);
    }
}


这比选项1略好,因为Dagger不必实例化每个实现,但是它仍然需要实例化所有依赖项,即使它们可能并非在所有情况下都使用。即使它们可以由Dagger创建,我也会自己创建对象。

This is slightly better than option 1 in that Dagger doesn't have to instantiate every single implementation, however it still needs to instantiate all of the dependencies even though they might not be used in all cases. I'm also back to creating the objects myself even though they could be created by Dagger.


  1. 创建每个实现一个模块并实例化相应的模块。所以类似于:

  1. Create one module per implementation and instantiate the appropriate module. So something like:

@Module
public FooImpl1Module {

    @Provides
    FooInterface provideFooImplementation(Context context) {
        return new FooImpl1(context);
    }
}


这没关系,但现在我在定义依赖于模块的组件时遇到了问题。

This would be fine, but now I have issues defining the component that depends on the module.

解决这个问题的最佳方法是什么?

What's the best way to tackle this problem?

一个建议是尝试选项1,参数包含在Lazy中。然后我最终只在一个上调用.get()。我会尽可能地尝试并发布结果

One suggestion has been to try option 1 with the parameters wrapped in Lazy. Then I only end up calling .get() on one. I'll try this out when I can and post the results

推荐答案

而不是 Lazy< T> ,使用提供商< T> 执行选项1。 懒惰< T> 只是一个提供商< T> ,它在本地进行备忘(带有必要的双重检查锁定),但是因为你知道你只会调用一个提供商一次,你可以改为注入提供者,并跳过同步开销。

Rather than Lazy<T>, do option 1 with Provider<T>. Lazy<T> is just a Provider<T> that memoizes locally (with the necessary double-checked locking), but because you know you'll only call one Provider exactly once, you can just inject the Provider instead and skip the synchronization overhead.

@Provides
FooInterface provideFooImplementation(
        Provider<FooImpl1> impl1,
        Provider<FooImpl2> impl2,
        ...,
        Provider<FooImpl10> impl10) {
    switch(state) {
        case STATE_1:
            return impl1.get();
        case STATE_2:
            return impl2.get();
        ...
        case STATE_10:
            return impl10.get();
    }
}

选项2可以使用,但你会有效跳过Dagger可以很容易地为你做的依赖连接,而选项3将无法按照规定工作,因为你的@Component注释需要你的模块列表作为编译时常量,让你的Dagger代码生成起作用。

Option 2 will work, but you'll effectively skip the dependency wiring that Dagger could easily do for you, and Option 3 won't work as stated because your @Component annotation needs your list of modules to be a compile-time constant for your Dagger code generation to work.

(如果您的绑定是一个或另一个形式的常量或零依赖类,则选项3的变体可以工作,因为那样您可以将模块的任意子类传入你的组件构建器。然而,Dagger只能分析超类模块中的绑定,如果你的@Provides方法实现采用不同的参数你会遇到麻烦,所以开关是我能想到的最好,最清晰的选择。)

(A variant of Option 3 could work if your binding were to a constant or a zero-dependency class of one form or another, because then you could pass in an arbitrary subclass of your Module into your Component builder. However, Dagger can only analyze the bindings in the superclass module, and you'd have trouble if your @Provides method implementations take different parameters as yours would, so the switch is the best and clearest alternative I can think of.)

这篇关于如何告诉Dagger 2基于X实例化哪个实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆