Как разрешить циклическую зависимость, все еще используя Dagger2?
У меня есть два класса, Foo<T>
и Bar
, которые зависят друг от друга, а также различные другие классы. Я использую Dagger-2 для инъекции зависимостей, но если я наивно добавляю циклическую зависимость, Dagger попадает в переполнение стека во время выполнения. Каков хороший способ рефакторинга классов, чтобы исправить это, все еще используя Dagger для внедрения всех других зависимостей и с минимальным дублированием и изменениями существующих вызовов?
3 ответа:
Самый простой выход-использовать
Lazy<T>
с одной стороны.Lazy<Foo> foo; Bar(Lazy<Foo> foo) { this.foo = foo; } // use foo.get(); when needed
После чрезмерного количества размышлений и бесед с коллегами, мы закончили тем, что сделали следующее:
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 }
Объясняя это - мы переместили фактическую логику Foo в родительский класс (FooWithoutDep), который взял циклическую зависимость в качестве настраиваемого поля, а не параметра конструктора. Тогда исходный класс просто содержал конструктор, который взял циклическую зависимость и вызвал сеттер. Другой класс, Bar, зависел от родителя (FooWithoutDep) и назывался сеттером явно, передавая себя (
this
). Это позволяет всем существующим ссылкам на класс оставаться неизменными, в то же время используя Dagger для внедрения всех зависимостей.Это казалось достаточно запутанным,чтобы стоило написать здесь.
Вот как я решил ее, без родительских классов.
Класс 1: Двигатель. (в интерфейсе компонента) @Обеспечивает публичный движок myEngine (контекст context) { возврат нового движка (контекст); }Класс 2: Части. Двигатель также нуждается в деталях экземпляра, но создание откладывается.
@Inject public Parts(Context context, Engine engine) { this.context = context; this.engine= engine; engine.setParts(this); }
Циклическая зависимость может быть достигнута, но один класс должен быть инициирован первым перед другим.
{[1] снова}, если это возможно, рефакторинг кода, чтобы избежать циклических Ди.