What is dependency injection?

  • Post published:May 23, 2020

Dependency injection (DI) is a technique used to help inject dependent objects of a class. It is also one of the techniques used to implement Inversion of Control (IoC).

Dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.

Wikipedia

Dependency injection involves four roles:

– the service object to be used

– the client object that is depending on the service(s) it uses

– the interfaces that define how the client may use the services

– the injector, which is responsible for constructing the services and injecting them into the client

Wikipedia

Dependency injection also allows for the separation of the creation of a client’s dependencies from the client’s behavior, thus allowing program designs to be more loosely coupled.

The three common ways of injecting dependencies into a client class are:

  • Constructor Injection – the dependencies are provided through a client’s class constructor.
  • Method Injection – the dependencies are provided through a public method of the client class.
  • Setter Injection – the dependencies are provided through a public property of the client class.

Example of Constructor Injection

Constructor injection allows client dependencies to be injected using the client’s constructor. Consider the below code base.

From the above code base it can be seen that the Logger class is tightly coupled to the EmailValidator class, since a concrete implementation of the Logger class is used within the EmailValidator class. Also, the EmailValidator is responsible for creating an instance of the Logger.

If the Logger class requires dependencies in a future feature, then the EmailValidator class will definitely break and will be required to provide these dependencies in order to create a new instance of the Logger class. This change will introduce more unconcerned logic in the EmailValidator.

To improve this design and to ensure that the EmailValidator has only a single responsibility, dependency injection with constructor injection can be used to inject a Logger dependency into the EmailValidator class.

Using the roles of dependency injection, the following solution can be constructed:

interfaceAn interface can be created for a logger. This interface will be the contract that is used between the EmailValidator and the Logger class. This interface shall be called ILogger.
serviceThe Logger class is known as the service class. This class will implement the ILogger interface. It is also known as a concrete implementation of the ILogger interface.
clientThe EmailValidator class is known as the client class. In this example, the EmailValidator has only one dependency, that is, an instance of the ILogger interface. An instance of the concrete implementation of the ILogger interface shall be injected into the EmailValidator class during run time.
injectorThere are many dependency injection frameworks (example Microsoft Dependency Injection, Autofac, StructureMap, etc.) that can be configured to associate the concrete Logger to the ILogger interface. These frameworks will handle the injector capabilities.

Consider the below possible constructor injection solution.

The above solution has now decoupled the Logger class from the EmailValidator class. The EmailValidator can focus on its intended behavior of validating email addresses and does not need to worry about constructing a Logger instance.

Example of Method Injection

Method injection allows client dependencies to be injected into a client’s public method.

Method injection could also be used to solve the tight coupling between the EmailValidator and Logger class defined above.

Consider the below possible method injection solution.

Method injection is useful and is normally used when only a single method in a client’s class requires a dependency.

Example of Setter Injection

Setter injection, also known as property injection, allows client’s dependencies to be set through a client’s public property.

Setter injection could also be used to solve the tight coupling between the EmailValidator and Logger class defined earlier in this article.

Consider the below possible setter injection solution.

As can be seen from the above class, an instance of the ILogger is injected using the public Logger set property.

Summary

Dependency injection is a powerful design pattern that allows development of loosely coupled software components, thus enhancing re-usability, extensibility, test-ability, simplicity and maintainability.

There are a number of dependency injection packages that assist with creating an injector container. Choosing the appropriate dependency injection package normally comes down to personal preference.

Further information on dependency injection can be found at the following link: