Dependency Injection - What it is, Why it is & How to use it

January 04, 2018

Dependency injection is a design pattern that allows us to create loosely coupled classes.
To understand loosely coupled classes, let us understand there opposite i.e. tightly coupled classes.

Tightly Coupled Classes Example

tight coupling between classes

Consider this two classes:
public class Class1: IClass1
{
 public IClass2 class2;

 public Class1()
 {
  class2 = new Class2();
 }
}

public class Class2: IClass2
{
}

instance of class 2 injected in class 1


As you can see, Class 1 instantiates the object of Class 2 in its constructor.

What if the logic for object instantiation for class 2 changes, class 1 also needs to be changed. This is called tight coupling between classes. To prevent such scenario, we use a design pattern called dependency injection.

What is dependency injection?

According to dependency injection, instead of instantiating the dependency object in a class, we just pass the dependency along with the object in its constructor.

Dependency Injection may also be called as Inversion Of Control (IoC) as it follows the Hollywood Principle
"Don't call us, We will call you."

Dependency Injection In Action

This can be well explained with the help of this example:

Consider the architecture of a MathsCalculator class such that it is the concrete implementation of interface IMathsCalculator. The MathsCalculator class uses a MathsService instance to compute mathematical calculations like SquareRoot, CubeRoot etc.

Here we will be using the dependency injection design pattern to decouple the two classes MathsCalculator and MathsService.

class MathsCalculator: IMathsCalculator
{
 IMathsService mathsService;

 MathsCalculator(IMathsService mathsServiceInstance)
 {
  mathsService = mathsServiceInstance;
 }

 float SquareRoot(float num)
 {
  float num = this.mathsService.sqrt(num);
  return num;
 }
}

void main()
{
 IMathsService mathsService = new MathsService();
 IMathsCalculator mathsCalculator = new MathsCalculator(mathsService);

 float result = mathsCalculator.SquareRoot(5);

 Console.WriteLine(" Square Root: "+result);
}
Observe the way we injected the mathsService instance in the MathsCalculator object's constructor.

This method to inject a dependent object in other class object is called as dependency injection.

The main objective of the concept is that the class using service instances need not know about the service instantiation. It all should know about using the instance.
Inversion of control is called so because it inverts the procedural programming flow.
Instead of the class looking for its dependency to instantiate, we provide the class object with the instantiated dependency.

Advantage of using Dependency Injection

The advantage of using Dependency Injection is it simplifies unit testing of the project. Consider if the service injected makes use of internet services, messaging services, etc such that they only need to be mocked in unit testing. While executing the unit testing, we can provide a mock internet service or a mock messaging service, so that we do not end up with actual messaging to real people while unit testing the code.

Now consider the scenario when there are nested dependencies injected like
Class1 has dependency Dependency1
Dependency1 has dependency Dependency2

The code for instantiating the instance of Class 1 would be like:
var instance = new Class1(new Dependency1(new Dependency2()));
This looks a bit confusing. To prevent this, we use DI Containers. I have created a separate article on DI Containers which can be found here.
Implementing the DI Containers >

You Might Also Like

0 comments