← Назад к вопросам

Когда стоит использовать Inject constructor в Dagger?

2.0 Middle🔥 161 комментариев
#Dependency Injection

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда использовать @Inject constructor() в Dagger?

@Inject constructor() — это аннотация, которая сообщает Dagger, как создавать экземпляры класса, когда они требуются в графе зависимостей. Это один из основных способов предоставления зависимостей, наряду с @Provides методами в модулях и @Binds для абстракций. Решение о его использовании основывается на нескольких ключевых факторах.

Основные сценарии использования @Inject constructor

1. Когда класс находится под вашим контролем

Используйте @Inject для классов, исходный код которых вы можете изменить (например, собственные ViewModel, Repository, UseCase). Это самый простой и декларативный способ. Dagger автоматически создаст фабрику для этого класса.

// Правильно: класс под нашим контролем
class UserRepository @Inject constructor(
    private val apiService: ApiService,
    private val cache: UserCache
) {
    fun getUser(id: String): User { ... }
}

2. Для внедрения зависимостей в конструктор

Это предпочтительный способ, соответствующий принципу инверсии зависимостей (Dependency Injection). Все необходимые зависимости явно объявляются в параметрах конструктора, что делает класс тестируемым и независимым от фреймворка.

// Зависимости явно объявлены
class PaymentProcessor @Inject constructor(
    private val validator: Validator,
    private val gateway: PaymentGateway,
    @Named("RetryCount") private val retryCount: Int
)

3. Когда зависимости могут быть предоставлены графом Dagger

Все параметры конструктора, помеченного @Inject, должны быть доступны в графе зависимостей (через другие @Inject конструкторы, @Provides методы или @Component dependencies). Если вы не контролируете какой-то класс (например, библиотечный Retrofit), используйте @Provides.

4. Для избежания boilerplate кода в модулях

@Inject constructor сокращает количество кода. Без него пришлось бы создавать модуль с методом @Provides.

// Вместо этого в модуле:
// @Module
// class AppModule {
//     @Provides
//     fun provideRepository(api: Api): Repository = RepositoryImpl(api)
// }

// Можно просто:
class RepositoryImpl @Inject constructor(private val api: Api) : Repository

Когда НЕ стоит использовать @Inject constructor

  • Классы сторонних библиотек: Вы не можете аннотировать их конструктор. Используйте @Provides.
    @Module
    object NetworkModule {
        @Provides
        fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder().build()
    }
    
  • Интерфейсы или абстракции: Для них используйте связку @Binds в модуле.
    @Module
    interface RepositoryModule {
        @Binds
        fun bindRepository(impl: UserRepositoryImpl): UserRepository
    }
    
  • Когда логика создания объекта сложная: Если экземпляр нельзя создать простым вызовом конструктора (требуется конфигурация, выбор реализации по условию), используйте @Provides.
    @Provides
    @Named("Cached")
    fun provideCachedRepository(
        networkRepo: NetworkRepo,
        cache: Cache
    ): Repository = if (cache.isValid) CachedRepo(cache) else networkRepo
    
  • Для примитивных типов или строк: Они требуют квалификаторов (например, @Named) и обычно предоставляются через @Provides в модуле.

Практические рекомендации и вывод

  • Отдавайте предпочтение @Inject constructor для ваших собственных классов. Это делает код чище и следует конвенции Dagger/Hilt.
  • Помните о правиле "один аннотированный конструктор": В классе может быть только один конструктор, отмеченный @Inject.
  • Используйте @Inject для полей (field injection) только когда необходимо, например, для классов Android (Activity, Fragment), где конструкторы недоступны. Но саму зависимость лучше запрашивать в конструкторе.
  • В Hilt использование @Inject constructor() становится практически стандартом для внедряемых классов, так как Hilt генерирует все необходимые компоненты автоматически.

Итог: @Inject constructor — ваш основной инструмент для пометки классов, которые Dagger может создавать самостоятельно. Его использование приводит к более чистому, поддерживаемому и тестируемому коду, минимизируя ручную конфигурацию в модулях. Для всех остальных случаев, когда прямое внедрение через конструктор невозможно, применяйте @Provides и @Binds в модулях Dagger.