Как работать со многими компонентами кинжала при использовании зависимости компонентов

#dagger-2 #dagger

Вопрос:

У меня есть граф объектов кинжала, который построен из множества графов объектов меньшего размера с использованием зависимостей компонентов. Каждый компонент, по сути, представляет собой свой собственный граф объектов, и он предоставляет несколько объектов для удовлетворения зависимостей других компонентов в дереве. Графики объектов внутри каждого компонента не имеют значения (поэтому я вообще не говорю о Кинжале @Modules ).

введите описание изображения здесь

 @Component(dependencies = [RepositoryComponent::class])
interface AppComponent {
 

(Аналогичная настройка для других компонентов)

С помощью vanilla Dagger я должен создавать каждый компонент, вызывая их соответствующий конструктор.

 val appComponent = DaggerAppComponent
  .builder()
  .build()
 

(Обычно в Application классе.)

Но мне также нужно указать зависимость компонента, создав Factory и добавив к его create методу

 @Component(dependencies = [RepositoryComponent::class])
interface AppComponent {
    @Component.Factory
    interface Factory {
        fun create(repositoryComponent: RepositoryComponent): AppComponent
    }
}   
 

а затем вызываем метод фабрики create вместо конструктора

 val appcComponent = DaggerAppComponent
  .factory()
  .create(repositoryComponent = ...)
 

Все это стандартная зависимость от компонентов, более или менее прямо из документов Dagger

Все становится сложнее , когда вы понимаете, что вам нужно воспроизвести все это для RepositoryComponent , ApiComponent и DatabaseComponent . Окончательное «создание компонента» начинает расширяться:

 val apiComponent = ApiComponent.Factory
    .create()
val databaseComponent = DatabaseComponent.Factory
    .create()
val repositoryComponent = RepositoryComponent.Factory
    .create(
        apiComponent,
        databaseComponent
    )
val appComponent = AppComponent.Factory
    .create(repositoryComponent)
}
 

Вы можете себе представить, что это не будет масштабироваться, как только мое приложение будет состоять из 100 компонентов кинжала. Мое приложение знает обо всем дереве компонентов. Я сливаю api код на app уровень. Есть ли в любом случае возможность уменьшить эту котельную плиту? Как другие команды справляются с этим в более крупных приложениях?

Ответ №1:

Во-первых, это очень много компонентов. В промежутке между повторением шаблонов и невозможностью удалить неиспользуемые привязки, возможно, вам захочется дважды проверить, не теряете ли вы значительную экономию, перейдя на структуру со значительно меньшим количеством компонентов верхнего уровня (в отличие от подкомпонентов).

Предполагая, что вы хотите независимости компонентов, по некоторому определению сложность не может быть уменьшена: например, вы можете захотеть или не захотеть, чтобы вы DatabaseComponent повторно использовались между репозиториями. Когда вам начинает нужно выражать сложные зависимости с проблемами области видимости, это начинает звучать как задача, которую должен был решить Dagger: у вас может быть компонент верхнего уровня, на котором лежит исключительная ответственность за область и создание экземпляров зависимостей для вашего компонента приложения.

Наконец, я не уверен, что согласен с вашей озабоченностью здесь:

Мое приложение знает обо всем дереве компонентов. Я сливаю код api на уровень приложения.

Хотя важно инкапсулировать отдельные части вашего приложения, мы также можем предположить, что исключительная ответственность какого-либо компонента должна заключаться в настройке вашего приложения и объединении его отдельных компонентов. Создание экземпляра этого на верхнем уровне («уровень приложения») не кажется мне ошибкой дизайна, при условии, что вы придерживаетесь абстракции, которую представляет ваш ApiComponent. Таким образом, другие слои, такие как ваш компонент репозитория, не имеют значения, как реализован ваш компонент Apicom, где он подключен или как он решается. Ваша альтернатива-отказаться от внедрения зависимостей, чтобы компонент RepositoryКомпонент создавал свой собственный компонент Apicom, но если вы хотите, чтобы все ваши объекты совместно использовали компонент APICOM, вам придется где-то его подключить. До тех пор, пока вы не допускаете утечки других проблем в вашу функцию подключения компонентов, ваша текущая реализация кажется такой же разумной, как и любая другая.