Apakah Koin Dependency Injection atau Service Locator?

pengantar


Pengembangan Android untuk DI secara tradisional menggunakan Dagger 2 , kerangka kerja pembuatan kode yang sangat kuat. Tetapi ada masalah: sulit bagi pemula untuk menggunakannya. Prinsip DI itu sendiri sederhana dan mudah, tetapi Belati mempersulitnya. Anda dapat mengeluh tentang penurunan mutlak dalam literasi programmer, tetapi masalahnya tidak akan hilang dari ini.


Dengan munculnya Kotlin, menjadi mungkin untuk menulis hal-hal yang nyaman yang hampir tidak mungkin menggunakan Java. Salah satu dari hal-hal ini adalah Koin , yang bukan DI, tetapi Service Locator, yang diperlakukan oleh banyak orang sebagai anti-pola , itulah sebabnya banyak orang pada dasarnya tidak menggunakannya. Tetapi sia-sia, karena memiliki API yang sangat ringkas yang menyederhanakan penulisan dan pemeliharaan kode.


Dalam artikel ini, saya ingin membantu para pemula mencari tahu perbedaan antara Dependency Injection dan Service Locator, tetapi bukan Koin itu sendiri.


Ketergantungan injeksi


Pertama-tama, apa itu Injeksi Ketergantungan? Dengan kata sederhana, ini adalah ketika suatu objek menerima dependensi dari luar, daripada membuat atau mengekstraksi sendiri. Saya akan memberi contoh. Misalkan kita memiliki antarmuka Engine, implementasinya, dan juga kelas Caryang bergantung pada Engine. Tanpa DI, akan terlihat seperti ini


interface Engine
class DefaultEngine: Engine

class Car {
  private val engine: Engine = DefaultEngine()
}

fun main() {
  val car = Car()
}

Jika kita menulis ulang kelas Carmenggunakan pendekatan DI, maka ini bisa terjadi:


class Car(private val engine: Engine)

fun main() {
  val car = Car(DefaultEngine())
}

Sederhana - kelas Cartidak tahu dari mana implementasi berasal Engine, sementara mengganti implementasi ini sangat mudah, hanya meneruskannya ke konstruktor.


Pencari layanan


Service Locator. – , . Koin ServiceLocator, , API.


object ServiceLocator {
  fun <reified T> register(factory: () -> T) { ... }
  fun <reified T> resolve(): T { ... }
}

, . :


interface Engine
class DefaultEngine: Engine

class Car {
  private val engine: Engine = ServiceLocator.resolve()
}

fun main() {
  ServiceLocator.register<Engine> { DefaultEngine() }
  val car = Car()
}

DI, Car , , – Car, . :


interface ServiceLocator {
  fun <reified T> register(factory: () -> T)
  fun <reified T> resolve(): T
}

class DefaultServiceLocator: ServiceLocator { ... }

class Car(private val serviceLocator: ServiceLocator) {
  private val engine = serviceLocator.resolve<Engine>()
}

fun main() {
  val serviceLocator = DefaultServiceLocator()
  serviceLocator.register<Engine> { DefaultEngine() }
  val car = Car(serviceLocator)
}

, Car , . .. . :


class Car(private val engine: Engine)

fun main() {
  ServiceLocator.register<Engine> { DefaultEngine() }
  val car = Car(ServiceLocator.resolve<Engine>())
}

Ini adalah Injeksi Ketergantungan murni. Dengan Koin, akan terlihat seperti ini:


interface Engine
class DefaultEngine: Engine
class Car(private val engine: Engine)

fun carModule() = module {
  factory<Engine> { DefaultEngine() }
  factory { Car(get<Engine>()) }
}

fun main() {
  val koin = startKoin {
    modules(carModule())
  }.koin

  val car = koin.get<Car>()
}

Sayangnya, kita masih perlu menghubungi Koin untuk dependensi, tetapi ini sama sekali tidak bertentangan dengan prinsip-prinsip Injeksi Ketergantungan.


MEMPERBARUI Atas permintaankranid Saya akan memberikan contoh paling sederhana pada Dagger 2.


interface Engine
class DefaultEngine: Engine
class Car @Inject constructor(private val engine: Engine)

@Module
class AppModule {
  @Provides
  fun provideEngine(): Engine = DefaultEngine()
}

@Component(modules = [AppModule.class])
interface AppComponent {
  fun car(): Car
}

fun main() {
  // DaggerAppComponent –  ,   Dagger
  val daggerComponent = DaggerAppComponent.create()
  val car = daggerComponent.car()
}

All Articles