What is Dependency Injection Design Pattern?

The software world is getting more robust and smart with blooming innovative ideas every day. Every technology is lightened by this smartness which reduces the heavy and complex mechanisms. Emerging frameworks are best examples of those innovations. Those are capable of making the designers and developers’ lives less stressful with many automated features. Containers are a core part of these frameworks which assemble and manage components from different layers and external entities. Containers use several design principles to enhance their functionalities. Dependency Injection is a key principle in this context which simplifies complexities in systems.

How Dependency Matters?

Dependency is the need of data and services of one entity to continue the execution of other entity. The dependent entity will be unusable or worthless without the existence of service entity. In the programming world, if one object requires data and service of another object for its’ functioning we call it as a dependency and the service receiver is called as the dependent.

 

What is dependency
What is dependency

What is Dependency Injection Design Pattern?

The dependency injection design pattern is a way of object configuration to obtain independency of each object responsibilities. In there, a dependent object is configured from the outside instead of configuring inside the same object. It enables loose coupling of applications with a set of general guidelines and it is not a library, framework or tool. This also popular as Hollywood principle – “Don’t call us – we’ll call you”.

Instead of hard-coding dependencies, such as specifying a database server, list of services are injected into the component via a third party. So that component needs not to worry about creating and handling those external services. It leads to many benefits especially when the system gets larger and complex. Most of the time containers are used to manage and automate the construction and lifetimes of interdependent objects.

Origin of Dependency Injection

This is the code implementation style of famous ‘Dependency Inversion Principle’ which is the last design principle from the 5 SOLID principles of object oriented design by Robert C. Martin. This principle ensures that any dependency of an object should be provided externally instead of dependency internally created within the same object. The two main points of dependency inversion principle are,

  1. High-level modules should not depend on low-level modules that is a module should depend on abstractions, not concrete details.
  2. Abstractions should not depend upon details. Details should depend upon abstractions.

Hence, Dependency Injection design pattern invents approaches to fulfil above conditions of the dependency inversion principle.

What is Injection?

Injecting is inserting or passing the data or service to the dependent entity. A dependency can be pushed into the class from the outside.

How does Dependency Injection work?

Dependencies can be injected into the object via several methods. All those methods should ensure external object instantiation without disturbing the client code. The client or dependent object delegates the responsibility of providing its dependencies to external code. This external code could be called as ‘Injector’. Injector plays the mediator role to introduce client and its dependency to each other. The client need not call or deal with injector code. It is done by separate service. Primary approaches for injecting the dependencies are via constructors and setter methods. But now there are specialized dependency injection frameworks as well to acquire this requirement. Usually, a container manages the lifecycle of objects and their dependencies based on a configuration file or annotations.

Simple Real Life Example

Can you live without using a toothbrush? It is a – can’t live without, item on your personal care item list. But, have you ever thought how and where your toothbrush was made? Most probably, ‘No’ or ‘Who cares?’ will be your answers. Of course, it is totally out of our scope. Making a standard toothbrush is a complex, time-consuming process. It needs a list of production materials and labor aligned with a standard process before coming to our hand. So, no way we can build it at our home. The toothbrush manufacturer does it for us. We just have to buy it from the shop and use it. In this scenario, you depend on the toothbrush to clean your teeth. Since, you can’t make the toothbrush by your own, the manufacturer makes that for you that is manufacturer inject the toothbrush dependency on yourself so that you can use it to keep you clean. Likewise, dependency injection is a way of providing an external data or service without interrupting individual existence of an entity.

Without Dependency Injection

Let’s assume that small business wants to keep track of their employees. It creates the ‘Employee’ class and stores the relevant data like name, id, address and phone number. Since the address contains several parts and it may vary depending on certain conditions designers decide to make it as a separate class. Now, when you are creating or using an employee object, an address object should be instantiated within the employee object in order to complete the proper behavior of employee object.

Let’s look at the code samples,

 

Dependency Injection Code Sample
Dependency Injection Code Sample

Problem

In any case, if the ‘Address’ class was modified as to insert another part to the address employee class should reflect necessary changes accordingly and re-compile again to function properly. Also, if address object gets to depend on any other external class that also will have to consider when managing the employee class. So, this makes the maintenance of the system very difficult.

Solution

Find a way to decouple the Address object from the Employee object. Separating each class responsibilities independently, by introducing a way to inject the service from Address object to Employee object. So that Employee object can behave independently.

Methods of Injecting Dependency

There are 3 main methods in use when implementing a less coupled code with the help of dependency injection design pattern. Developer selects a suitable approach depending on conditions at the hand.

  1. Constructor Injection – Dependencies are inserted via class constructor
  2. Setter Injection – Client or dependency provider provides a setter method which is used by the injector()
  3. Interface Injection – The dependency provider introduces an injector method that will inject the dependency into the client

Let’s get to know the above method using the Employee/Address example. In all the below examples ‘Employee’ class is de-coupled from ‘Address’ class and ‘Address’ class also exists independently without interacting tightly with ‘Employee’ class. The address attribute or the dependency has to be injected to the dependent component via dependency injection mechanism.

Traditional approach to insert address to the employee object,

‘Employee’ class is responsible to initialize the address object and use it to send the greeting card. This is a hard-coded dependency, if there are any internal changes to ‘Address’ class, it will require code changes and recompilation of ‘Employee’ class as well. If the ‘Address’ object is used in any other classes in the same manner, all those classes have to be changed. These will make the application difficult to extend, maintain and test.

Testing class contains below code,

Constructor Injection

In this approach, the dependencies are provided via the constructor arguments. Basically, an argument is an object reference of the dependency class. The constructor will be called only upon class compilation and it ensures that the dependency won’t change during the object lifetime. Hence, this is good for mandatory dependencies, ensuring the object is fully ready to be used upon construction. Here the ‘Address’ object is created outside and injected to ‘Employee’ object as a constructor parameter, so ‘Employee’ don’t have to worry about address object creation.

Setter Injection

In this approach, setter method is used to pass the externally instantiated object to the required class. Also, it is encouraging to apply optional dependencies in setter injection. The dependent class should be able to function even without the setter arguments. These dependencies can be changed even after the object is instantiated and it won’t create a new instance always like with constructor injection. Hence, setter injection is flexible than constructor injection.

Interface Injection

This approach takes the use of an interface to clearly separate the responsibility. Here, the client is implementing the interface with the dependency and override its method to achieve the required functionality. Here, the dependency is given a chance to control its own injection.

Dependency Injection Containers

A container is an external entity which is responsible for object instantiation, configuration and overall object management. A container is usually treated as a lightweight execution ground to keep smooth object handling. It enables object creation within itself rather than wiring client code like factory pattern. If we consider our Employee/Address example, we can simplify object creations and injections with the help of a container.

 

Container Responsibilities
Container Responsibilities

Advantages of Dependency Injection

  • Individual classes in the system can stand alone without depending on other external implementations
  • Improves flexibility to use alternative implementation of another service without recompiling the application
  • Ability to use an IOC container to handle services including selecting and injecting dependency
  • Improve the flexibility, reusability and readability of the code
  • Ability to use mock objects in testing without complicating the required object creation
  • Reduce coupling of objects, eliminating the need of client code change for every dependent class modification
  • Boilerplate Code reduction in application classes because all work to initialize dependencies is handled by the injector component

Disadvantages of Dependency Injection

  • Difficulty in code tracing or reading due to separation of behavior from construction, it will require more effort to know how the system performs
  • Require higher upfront designer and developer effort to identify each dependency and clients

As in the above article, dependency injection is a wide concept to learn before applying to any code. There are several new approaches like annotations and configuration files to acquire the dependency injection design pattern easily but the core concept remains same and intact for all those approaches. That’s why you have to completely understand the inner mechanism of dependecy injection with a clear mind.

6 thoughts to “What is Dependency Injection Design Pattern?”

  1. Spring dependency injection is one of the most used example of this pattern. Was asked about dependency injection recently in interview. Thanks for explaining.

    1. A short summary, In Factory pattern, creation of objects is done by the code itself while in Dependency Injection this responsibility is shifted to different code(may be a class or a different framework).

Leave a Reply