Dependency Injection - What is Dependency Injection?

Published August 16, 2020

In this post, we will learn about Dependency Injection.
before going to learn about DI, first what is the problem we are facing to go with DI.

 

Let's check below example

 

fun main()
{

    val car=Car();
    car.start()

}
class Car{
  var engine=Engine();
    fun start()
    {
        engine.start()
    }
}

class Engine{

    fun start()
    {
        System.out.println("Engine started")
    }
}

 

In the above, we have a Car which contains a method start() to start the Car.
To start the car we need to start its Engine, so we created its Engine class object within the Car Object

So now to start the car we need to call start() method, so we are creating the Engine Object inside Car class.

with the car object, we are calling the start() to start the car. Everything is working well, but here Car and Engine both are bound with the tight couples.

 

This is the typical way of creating the dependent object. By this way, we have below problems

  • Testing the program is very difficult
  • Maintaining the code is very difficult

 So dependency injection will reduce coupling between these two

 

Dependency Injection

 

What is Dependency Injection?

Dependency Injection (DI) is a design pattern used to implement IoC. It allows the creation of dependent objects outside of a class and provides those objects to a class in different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them

The Dependency injection pattern involves 3 types of classes

  • Client class
  • Server class
  • Injector class

So how the Dependency Injection will provide Engine object to Car class.
In DI we will not create Engine Object inside Car class, we will pass Engine object inside Car Constructor

 

Let's check the above code with DI

fun main()
{

    val car=Car(Engine());
    car.start()

}
class Car{
   lateinit var engine:Engine;
    constructor( engine:Engine)
    {
        this.engine=engine;
    }
    fun start()
    {
        engine.start()
    }
}

class Engine{

    fun start()
    {
        System.out.println("Engine started")
    }
}

 

Now Everything working fine and the car has started.

 

Scenario 2
Let's check one more scenario without Dependency Injection

fun main()
{

    val car=Car();
    car.start()

}
class Car{
    var engine:Engine=PetrolEngin();
    
    fun start()
    {
        engine.start()
    }
}


class PetrolEngin:Engine
{
    override fun start() {
        System.out.println("Car Engine Started")
    }

}
class DieselEngin:Engine
{
    override fun start() {
        System.out.println("Diesel Engine Started")
    }

}
interface Engine{

    fun start();
}

 

 

In the above, if we want to start the Car Engine/Diesel engine it will depend on Car class.

To overcome this we will modify the above code with Dependency Injection like below

 

package com.rrtutors.diexample

fun main()
{

    val car=Car(PetrolEngin());
    car.start()
    val car2=Car(DieselEngin());
    car2.start()

}
class Car{
    var engine:Engine;
    constructor( engine:Engine)
    {
        this.engine=engine;
    }
    fun start()
    {
        engine.start()
    }
}


class PetrolEngin:Engine
{
    override fun start() {
        System.out.println("Car Engine Started")
    }

}
class DieselEngin:Engine
{
    override fun start() {
        System.out.println("Diesel Engine Started")
    }

}
interface Engine{

    fun start();
}

 

So now we can start which car PetrolEngin or DieselEngine.

So this is Manual Dependency Injection. We have other Techniques to provide Dependency Injections

we will Learn about Dagger Dependency Injection in our coming series

 

Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

465 Views