How to resolve a circular dependency while still using Dagger2?

后端 未结 3 1477
猫巷女王i
猫巷女王i 2021-02-12 15:29

I have two classes, Foo and Bar, which depend on each other, as well as various other classes. I am using Dagger-2 for dependency injection, b

相关标签:
3条回答
  • 2021-02-12 16:05

    This is how I resolved it, without parent classes.

    Class 1: Engine. (in component interface)

    @Provides
    public Engine myEngine(Context context) {
        return new Engine (context);
    }
    

    Class 2: Parts. Engine also needs Parts instance but the creation is delayed.

    @Inject
    public Parts(Context context, Engine engine) {
        this.context = context;
        this.engine= engine;
        engine.setParts(this);
    }
    

    Circular dependency can be achieved but one class must be initiated first before the other.

    Again, if possible, refactor code to avoid circular DI.

    0 讨论(0)
  • 2021-02-12 16:07

    After an excessive amount of thought and talks with coworkers, we ended up doing the following:

    class Foo<T> extends FooWithoutDep<T> {
        @Inject Foo(Bar bar, OtherDep1 dep1, OtherDep2 dep2) {
            super(dep1, dep2);
            setBarDep(bar);
        }
    }
    
    class FooWithoutDep<T> {
        //Field declarations elided
        @Inject FooWithoutDep(OtherDep1 dep1, OtherDep2 dep2) {
            //Normal constructor stuff
        }
        void setBarDep(Bar bar) { this.bar = bar; }
    
        //The rest of the actual logic
    }
    
    class Bar {
        //Field declarations elided
        @Inject Bar(FooWithoutDep<Thing> foo, OtherDep3 dep3) {
            this.foo = foo;
            this.foo.setBarDep(this);
            this.dep3 = dep3;
        }
    
        //Code that uses Foo and the other dependencies
    }
    

    Explaining this -- we moved the actual logic of Foo into a parent class (FooWithoutDep), that took the circular dependency as a settable field rather than a constructor parameter. Then the original class just contained a constructor that took the circular dependency and called the setter. The other class, Bar, depended on the parent (FooWithoutDep), and called the setter explicitly, passing itself (this). This enables all the existing references to the class to remain the same, while still using Dagger to inject all the dependencies.

    This seemed confusing enough to be worth writing up here.

    0 讨论(0)
  • 2021-02-12 16:19

    The easy way out is to use Lazy<T> on one side.

    Lazy<Foo> foo;
    
    @Inject
    Bar(Lazy<Foo> foo) {
        this.foo = foo;
    }
    
    // use foo.get(); when needed
    
    0 讨论(0)
提交回复
热议问题