Java Dagger 2子类具有比父类更具体的依赖项

Java Dagger 2子类具有比父类更具体的依赖项,java,android,dependency-injection,dagger-2,Java,Android,Dependency Injection,Dagger 2,我正在处理这样的对象层次结构: class Foo extends View { @Inject BaseDependency dep; Foo() // Default android view constructors { injectDependencies(); } protected void injectDependencies() { getApp().getFooComponent().injec

我正在处理这样的对象层次结构:

class Foo extends View
{
    @Inject BaseDependency dep;

    Foo() // Default android view constructors
    {
        injectDependencies();
    }

    protected void injectDependencies()
    {
        getApp().getFooComponent().inject(this);
    }
}


class ExtraBaseDependency extends BaseDependency
{
    @Inject
    ExtraBaseDependency() {}
}

class Bar extends Foo
{
    @Inject ExtraBaseDependency dep;

    @Override
    protected void injectDependencies()
    {
        getApp().getBarComponent().inject(this);
    }
}
我试图解决的问题是,我想在我更具体的“Bar”子类中使用更多方法的“ExtraBaseDependency”,我还想为Foo提供相同的对象,因为我正在从整个层次结构收集数据,以便在Bar中使用

我认为,通过重写injectDependencies()而不调用super,我可以为我的子类和它的父类提供它们所需的依赖项,但只有其中一个可以共享,但是Bar将获得对象更具体的接口,以便它可以完成它的工作

我看到的行为是,当它编译并运行时,我看到ExtraBaseDependency被构造了两次


My FooComponent和BarComponents具有不同的作用域和不同的模块,它们都是独立的。我不确定为什么在基类中没有得到与子类相同的实例。

您的两个字段将继续存在。Foo无法访问
Bar.dep
,但Bar可以通过
super.dep
访问
Foo.dep

Dagger将自动注入任何类型的超类型字段和方法, 所以,如果您调用
inject(Bar)
Dagger将注入Foo的字段和Bar的字段。(根据,您必须小心不要调用
inject(Foo)
,因为即使在运行时传入Bar实例,也只会注入Foo的字段。)

一些解决方案:

  • 随它去吧。Foo需要BaseDependency,Bar需要ExtraBaseDependency,Foo甚至可能会将该依赖项包保持私有,这样Bar就无法访问Foo的字段(如果字段是有状态的或涉及多个线程,这可能很重要)。如果你认为每个类都负责声明它自己的依赖关系,那么它是按预期的方式工作的,尽管是浪费的。

  • 确定依赖项的作用域(如果应该确定其作用域)。如果BaseDependency和ExtraBaseDependency在其组件的整个生命周期内保持一致,则可以使用作用域(例如,
    @Singleton
    @reusabled
    )对其进行标记,以减少依赖项的重复,或者,如果更适合自己管理单例实例,则只需在
    @模块中保存并返回一个实例。这不是一个好的通用解决方案,但是如果这是一项长期的工作,那么您也可以用它来解决这个问题

  • 如果可能的话,切换到构造函数参数(对于您的情况,它不是)。如果Bar扩展了Foo,Bar可以有一个
    @Inject
    -注释的构造函数,该构造函数使用您请求的特定依赖项显式调用Foo的构造函数。当然,对于Android视图,您需要成员注入;这是您的其他案例或其他读者的一个选项

  • 从Foo.dep中删除
    @Inject
    注释。dep的注入显然取决于它的子类,并且字段不是多态的,因此让Foo声明它的
    @Inject
    -注释字段对于您使用它的方式来说是不安全的

  • 将Foo重构为抽象基类。这也不是所有问题的通用解决方案,但您可以通过设计用于子类化和公开BasicFoo或DefaultFoo实现的Foo来解决类层次结构问题。这将使填充Foo.dep成为子类的责任,这可能更容易在类层次结构中进行推理


我感谢您的评论。我还没有尝试过将类抽象化,但我觉得这样应该可以工作。我不能让它保持原样,因为依赖项是一个“中介”类型的对象,并且类及其所有超类都需要相同。依赖项的作用域为自定义作用域。如果我从基类中删除@Inject,它将如何获得依赖关系?我还没有尝试将该类设置为基类,但这可能会奏效。我需要再调查一下。你能为BaseDependency提供一个抽象的getter吗?通过挖掘MembersInjectors,Dagger似乎选择使用两个不同的提供者来注入Foo和Bar。似乎拥有一个抽象类可能是唯一的出路。