What is Dependency Injection (DI)?

  • Dependency Injection (DI) is all about removing dependencies from your code.
  • DI is a pattern used for decoupling components and layers in the system.
  • Dependency injection means passing a dependent object as a parameter to a method/class, rather than having the method/class create the dependent object.
  • Dependency injection provides opportunities to -
    • simplify code,
    • abstract dependencies between objects,
    • and automatically generate dependent object instances.

How to achieve Dependency Injection (DI)?

This can be done in two step:

  1. Identify dependency

  2. Inject dependency when needed

    • Do not instantiate the dependencies explicitly in the class. Instead, declaratively express dependencies in the class definition. 
    • These dependencies are usually provided as interfaces for further decoupling and to support testability.
    • The pattern seeks to establish a level of abstraction via a public interface and to remove dependencies on components by supplying 'plug-in' architecture.
      • I.e. individual components are tied together by the architecture rather than being linked together themselves. 
    • Use a Builder object (Factory pattern) to obtain valid instances of the object's dependencies and pass them to the object during the object's creation and/or initialization. 
    • Dependencies can be injected using a constructor, property setter, an interface injection-
      • Constructor injection:

        • IoC pattern is implemented through injecting dependencies into a component when it is constructed, where the interface parameter which is referenced internally inside the class is been exposed through the constructor.
      • Setter injection:

        • It is enabling the injection of the interface implementation through the public property with the set block. 
      • Components of Dependency Injection: 

        • dependent consumer.
          • The dependent object describes what software component it depends on to do its work. 
        • Interface contracts.
          • Declaration of the component's dependencies.
        • An injector (aka a provider or container
          • Creates instances of classes that implement a given dependency interface on request.
          • The injector decides what concrete classes satisfy the requirements of the dependent object, and provides them to the dependent.

Explain Dependency Injection (DI) with Example?

Let's say we have ‘PDFCreator’ Class, which will create PDF for review as shown:

public class PDFCreator
 private Review review
 public PDFCreator()
 review= new Review();

Identify dependency-

In above code, we have created dependency with Review object. What if we have two different kinds of reviews? Or any other change in Review object that we don't want to expose to PDF Creator.

Inject dependency-

In order to remove this dependency, we would like to remove dependency and inject it whoever needed. To do this we modify the code as shown below.

public class PDFCreator
 private IReview iReview
 public PDFCreator(IReview iReview)
 this.iReview = iReview;

In this fix, we are now referring to Interface for ‘Review’ class and injecting it when we create ‘PDFCreator’ object, and because of this interface, we can inject different Review objects if any and removing the dependency of ‘Review’ class makes it ready for changes if any.


Pros of Dependency Injection (DI):

  • Useful for test-driven development - without DI it can be difficult to test modular system because the components under test are highly coupled to the rest of the system.
  • Best for developing a modular system whose components can be replaced without requiring recompilation.
  • Provides the ability to swap dependency implementations in different environments.
  • Provides a mechanism for sharing resources throughout an application.
  • Inversion of control is a practical way to reduce code duplication, and if you find yourself copying an entire method and only changing a small piece of the code

Cons of Dependency Injection (DI):

  • Use DI only when required - Do not stick it everywhere. If you will overuse this pattern, you will make very complicated design and even more complicated code.
  • Process may have a minor impact on performance

Examples of Tools / Libraries Used for Dependency Injection (DI):

  • Castle Windsor,
  • Unity

How Dependency Injection (DI) helps in Unit Testing?

It's very easy to write unit tests for your code because it depends on nothing else than the objects it accepts in its constructor/setters and you can easily initialize them with the right objects in isolation.