Dependency Injection, bağımlılık yaratan nesnelerin ayrılıp, bunların dışardan verilmesiyle (örneğin parametre yardımıyla), bağımlılığı ortadan kaldıran ya da minimize eden bir işlemdir.

Bu ayırma işlemini, Constructor (Kurucu) metotlar ile yapıyorsak buna “Constructor Injection”, setter metotlarıyla bu işlemi yapıyorsak “Setter Injection” veya “Field Injection” adı verilir.

Ayrıca, bağımlılık konusunu, Composition Kavramını anlatırken de belirtmiştim. Buraya tıklayarak tekar inceleyebilirsiniz.

Bir Araba ve Motor sınıfı düşünelim. Burada araba, motor sınıfına bağımlıdır, motor olmadan araba çalışamaz. Dolayısıyla bu bir bağımlılıktır.

class Araba
{
    var motor = Motor()
    
    fun calistir()
    {
        motor.calistir()
    }
}

class Motor
{
    fun calistir()
    {
        println("Motor çalışıyor..")
    }
}

fun main(args: Array<String>)
{
    var araba = Araba()
    araba.calistir()
}

Yukarıdaki örneğimizde görüldüğü üzere Araba sınıfı, motor sınıfına bağımlıdır. Dolayısıyla, bu bağımlılığı ortadan kaldırmak istiyoruz. Şimdi constructor yardımı ile bu bağımlılığı ortadan kaldıralım.

class Araba(var motor:Motor)
{   
    fun calistir()
    {
        motor.calistir()
    }
}

class Motor
{
    fun calistir()
    {
        println("Motor çalışıyor..")
    }
}

fun main(args: Array<String>)
{
    var motor = Motor()
    var araba = Araba(motor)
    araba.calistir()
}

Constructor yardımı ile Dependency Injection işlemini burada gerçekleştirdik. Bir de bu işlemi Field Injection ile gerçekleştirelim.

class Araba
{
    lateinit var motor : Motor
    
    fun calistir()
    {
        motor.calistir()
    }
}

class Motor
{
    fun calistir()
    {
        println("Motor çalışıyor..")
    }
}

fun main(args: Array<String>)
{
    var araba = Araba()
    araba.motor = Motor()
    araba.calistir()
}

Yukarıdaki kodumuzda da field injection yardımıyla, işlemimizi gerçekleştirdik. Örneğin, motor hybridmotor diye bir alt sınıf türettiğimizde dependency injection işlemi sayesinde araba sınıfında bir değişiklik yapmadan bu hybridmotoru da kullanabiliriz.

class Araba(var motor : Motor)
{    
    fun calistir()
    {
        motor.calistir()
    }
}

open class Motor
{
    open fun calistir()
    {
        println("Motor çalışıyor..")
    }
}

class hybridMotor : Motor()
{
    override fun calistir()
    {
        println("Hybrid motor çalışıyor.")
    }
}

fun main(args: Array<String>)
{
    var hybridmotor = hybridMotor()
    var araba = Araba(hybridmotor)
    araba.calistir()   
}

Dikkat edilirse, motor sınıfından ürettiğim hybridMotor sınıfını Araba sınıfında değişiklik yapmadan kullanabildim. 

Peki, neden Dependency Injection ve neden bu bağımlılıklardan kurtulmak istiyoruz?

Yukarıda da görüldüğü gibi, bir sınıf içerisinde başka bir sınıfa bağımlı olduğunda, bağımlı olunan sınıfta bir değişiklik, bağlı olan sınıfta da değişiklik gerektirir. Belki yukarıdaki örneğimizde tek bir tane sınıf için bu bağımlılık olayı dependency injection yapmadan düzeltilebilir. Ancak, birden fazla böyle sınıf olduğunu düşünürsek bu hiçte iyi bir çözüm olmayacaktır.

Dependency injection, kodun okunabilirliğini, sürdürebilirliğini, esnek olmasını ve test edilebilmesini kolaylaştırır.