What is Dependency Injection & why do we need it ?

  • Dependency injection is a technique used in software engineering to develop loosely coupled systems.
  • It is a technique that allows an object to receive other objects that it depends on by some other program than it explicitly calling the dependent object.
  • Let us understand why this is needed by an example. I have a Notification Interface which defines an abstract method sendNotification. The Implementation of this method is done by SMSNotification Class. Another class UserService, uses these classes to notify users.
  • In this design UserService is dependent on SMSNotification and it needs to know about SMSNotification to create an instance of this class
public class UserService {
    public static void main(String[] args) {
        Notification objNotification = new SMSNotification();
        objNotification.send("test@test.com","Test Message");
    }
}
  • What we want is , UserService to be only dependent on Notification Interface and not on SMSNotification implementation.Basically we want to decouple the implementation of UserService from any specific implementation of Notification like SMSNotification or EmailNotification
  • To improve the design in our example , we will pass the responsibility of creating instance of SMSNotification to some container class that manages UserService. When told to create an inject, container will inject an instance of SMSNotification by using UserService classes public with argument constructor. Therefore UserService class now need to have a public with-arguments constructor.This setup is called dependency injection.
  • With this our dependency situation will be like this
    • UserService has Notification
    • Container has UserService
    • Container has Notification
    • Container creates SMSNotification
    • SMSNotification is Notification
  • Now UserService class depends on Notification and not on SMSNotification
  • Apart from achieving decoupling , In case if other classes also has a dependency on Notification service, container can inject a single Notification interface into each class. This allows for sharing of one Notification instance between classes
  • One important activity of application development process is Unit Testing, which means testing or verifying the smallest scope or piece of code.
  • Testing an independent unit of code ensures that the code functions as it is supposed to work and will integrate well with rest of the application components. It is easy to test a unit if it does not depend on other parts of the system.
  • In our previous example, since we are explicitly making an object of SMSNotification we have no means to replace it with a mock object for testing
public class UserService {
    public static void main(String[] args) {
        Notification objNotification = new SMSNotification();
        objNotification.send("test@test.com","Test Message");
    }
}
  • To test this unit of code without sending SMS to any real users, we don’t want to create an actual SMSNotification object. This can be solved using dependency injection which will inject a mock SMSNotification Object
  • Dependency injection can be enabled by passing the dependencies into a class via its constructor’s parameters.
public class UserService {
    Notification objNotification;
    public UserService(Notification objNotification) {
        this.objNotification =objNotification;
    }
  • This way our test can inject a mock SMSNotification object instead of having to instantiate an actual instance of SMSNotification class.
  • Therefore, to sum it up the 4 important roles in this design are
    • The service you want to use – Example SMSNotification
    • The client that uses the service – Example UserService
    • An interface that’s used by the client and implemented by the service – Example Notification
    • The injector which creates a service instance and injects it into the client.- Example a framework like Spring Framework
  • Frameworks like Spring, Play, Weld etc plays the role of injector or the container which injects these dependencies
  • To summarize here are the key benefits
    • Makes the system loosely coupled as it decouples the implementations of classes from the implementations of those classes’ dependencies.
    • Allows code to be testable with different mock implementation
    • Allows sharing of a single dependency between many classes, when applicable.

Thank You !!!

5 thoughts on “What is Dependency Injection & why do we need it ?

  1. You say “since we are explicitly making an object of SMSNotification we have no means to replace it with a mock object for testing”. Can you please elaborate on why it is so.
    In this non-DI version of the class being tested
    Notification objNotification = new SMSNotification();
    what’s the problem in using mock SMSNotification class in place of an original production SMSNotification class?

Leave a Reply