Dependency Injection is a design pattern used to implement IoC. Dependency Injection separates the creation of a client’s dependencies from the client behaviour , which allows program design to be loosely coupled and to follow the dependency inversion and single responsibility principles.
- Dependency injection involves four rules:-
- The service objects(s) 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.
Any object that may be used can be considered a service. Any objects that uses other objects can be considered a client.
The interfaces are the types of client expects its dependencies to be. They may truly be interface types implemented by the services but also may be abstract classes or even the concrete services themselves.
The client should have no concrete knowledge of the specific implementation of its dependencies.It should only know the interface’s name and API. As a result , the client do not need to change even if what is behind the interface changes.However if the interface is refactored from being a class to an interface type or vice versa , the client needs to be recompiled.This is significant if the client and services are published separately. This unfortunate coupling is one that dependency injection cannot resolve.
The injector injects the service into the client.An injector may connect together a very complex object graph by treating an object like a client and later as a service for a client.
Example(Without Dependency Injection)
I will be providing a simple example of a English Language class.
We have a English Language class which is used by another class to print English Sentences.
This class is referenced by our InternationalLanguage class.
The EnglishLanguage class is referred and initialized in our InternationalLanguage class . Here’s our main class:-
Here’s the output when we run this class:-
At first look everything looks good.But our design is not flexible enough to incorporate more language class.For example if we want to add a french language class then we will need to create a new class and modify our InternationalLanguages class to refer to the FrenchLanguage class.
The EnglishLanguage class is tightly coupled with the InternationalLanguages class.We should be able to add a new Language class without making any changes in our InternationalLanguages class.That’s why dependency injection is required.
Example(With Dependency Injection)
We create a new interface called Language.
We create two classes ,one for English Language and another for French Language and implement the above interface.
And we refer the interface in our class (WorldLanguage.java) .Here we are using constructor injection to inject the required dependency(service) in the WorldLanguage class.
Here’s our main class:-
If we want to add any other language , we just need to create another class which implements the Language class and no changes will be required in the WorldLanguage class. The interface is referred in the class and the specific class is passed to the WorldLanguage class at run time rather than compile time.
There are three ways to inject the service in your client class:-
Constructor Injection:- The dependency is injected through the client’s constructor.This is the one which we used in our example.
Setter Injection:- The client exposes a setter method that the injector uses to inject the dependency.
Interface Injection:- The dependency interface provides an injector method that will inject the dependency into any client passed into it.Client must implement an interface that exposes a setter method that accepts the dependency.
That’s all about Dependency Injection .Happy Coding everyone 🙂