Внедрение в случайный конструктор против внедрения зависимостей - PullRequest
4 голосов
/ 13 июня 2019

Хорошо, поэтому я решил поближе взглянуть на реализацию тестов junit в моем проекте. Затем я наткнулся на статью, в которой написано о том, как важно использовать фреймворки внедрения зависимостей, такие как Dagger2 и Koin , чтобы упростить тестирование.

Я пытался прочитать - Что именно DI . Я понимаю это как способ разрешения зависимых объектов класса A (например, класса B и класса C).

То, что я сейчас делаю, обычно таково:

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

Итак, какие преимущества я бы получил, если бы начал использовать Dagger 2 сейчас? Может, простое сравнение кода сделает это понятнее? Заранее спасибо.

Активность:

val someRepository = SomeRepository()
viewModel.init(someRepository) 

В ViewModel:

class SomeViewModel : ViewModel {

    private lateinit var repository: SomeRepository

    fun init(val someRepo: SomeRepository) {
        this.repository = someRepo
    }

}

Ответы [ 2 ]

5 голосов
/ 20 июня 2019

Dagger способствует развязке зависимостей с собственным графом зависимостей. Нам нужно сказать кинжалу, как классы могут быть сгенерированы, например. он принимает параметр конструктора. После определения он проходит через все зависимости и начинает создавать их с низкого уровня. Если мы не можем ввести какую-либо зависимость в конструктор, например, Модифицируя, мы можем вручную указать кинжалу, как создать экземпляр if с аннотацией @Provides.

Давайте рассмотрим пример:

Зависимость # 1 - Индивидуальные модули

@Module
class NetworkModule {

 @Provides
 fun provideRetrofit() : Retrofit  

}

Зависимость # 2 - Зависит от Зависимость # 1

class ApiService constructor (@Inject retrofit: Retrofit){
}

Зависимость # 3 - Зависит от Зависимость # 2

class SomeRepository constructor (@Inject apiService: ApiService){
}

Зависимость # 4 - Зависит от Зависимость # 3

class SomeViewModel constructor (@Inject someRepository: SomeRepository) : ViewModel {
}

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

class MainAcitivty : AppCompatActivity(){

 @Inject someRepository: SomeRepository

}

Минусы с вашим текущим подходом:

val someRepository = SomeRepository()
viewModel.init(someRepository) 
  1. Вы будете создавать новый экземпляр SomeRepository() снова и снова в разных видах деятельности
  2. Если SomeRepository() имеет какую-либо зависимость, они также будут созданы несколько раз
  3. Вы делаете крепкую связь. Будет очень сложно протестировать SomeRepository() без его зависимостей. В модульном тестировании мы заинтересованы в тестировании модуля, а не его зависимостей.
1 голос
/ 20 июня 2019

Pro1: С точки зрения непрофессионала, DI важен для написания разделенного кода, который облегчает написание модульных тестов.

Pro2: он также абстрагирует зависимости объекта от родительского класса. Например, в вашем случае использования Activity напрямую не использует SomeRepository, но все же необходимо знать об этом. Но вместо этого, если вы использовали инжектор конструктора следующим образом:

class SomeViewModel constructor (@Inject someRepository: SomeRepository) : ViewModel {
}

вашему классу активности просто нужно иметь дело с объектом SomeViewModel, и любые зависимости, используемые SomeViewModel, его не касаются.

Pro3: DI упрощает создание и доступ к одноэлементным объектам. Просто определите класс, как показано ниже, и вы можете получить единственный экземпляр класса MySingleton в любом месте вашего приложения.

@Singleton
class MySingleton @Inject constructor() {}

OR

@Provides @Singleton mySingleton() {}
...