by Bhavya Karia
In software engineering, dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service).
That’s the Wikipedia definition but still, but it’s not particularly easy to understand. So let’s understand it better.
Before understanding what it means in programming, let’s first see what it means in general as it will help us understand the concept better.
Dependency or dependent means relying on something for support. Like if I say we are relying too much on mobile phones than it means we are dependent on them.
So before getting to dependency injections, first let’s understand what a dependency in programming means.
When class A uses some functionality of class B, then its said that class A has a dependency of class B.
In Java, before we can use methods of other classes, we first need to create the object of that class (i.e. class A needs to create an instance of class B).
So, transferring the task of creating the object to someone else and directly using the dependency is called dependency injection.
Why should I use dependency injection?
Let’s say we have a car class which contains various objects such as wheels, engine, etc.
Here the car class is responsible for creating all the dependency objects. Now, what if we decide to ditch MRFWheels in the future and want to use Yokohama Wheels?
We will need to recreate the car object with a new Yokohama dependency. But when using dependency injection (DI), we can change the Wheels at runtime (because dependencies can be injected at runtime rather than at compile time).
You can think of DI as the middleman in our code who does all the work of creating the preferred wheels object and providing it to the Car class.
It makes our Car class independent from creating the objects of Wheels, Battery, etc.
There are basically three types of dependency injection:
- constructor injection: the dependencies are provided through a class constructor.
- setter injection: the client exposes a setter method that the injector uses to inject the dependency.
- interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.
So now its the dependency injection’s responsibility to:
- Create the objects
- Know which classes require those objects
- And provide them all those objects
If there is any change in objects, then DI looks into it and it should not concern the class using those objects. This way if the objects change in the future, then its DI’s responsibility to provide the appropriate objects to the class.
Inversion of control —the concept behind DI
This states that a class should not configure its dependencies statically but should be configured by some other class from outside.
It is the fifth principle of S.O.L.I.D — the five basic principles of object-oriented programming and design by Uncle Bob — which states that a class should depend on abstraction and not upon concretions (in simple terms, hard-coded).
According to the principles, a class should concentrate on fulfilling its responsibilities and not on creating objects that it requires to fulfill those responsibilities. And that’s where dependency injection comes into play: it provides the class with the required objects.
Note: If you want to learn about SOLID principles by Uncle Bob then you can head to this link.
Benefits of using DI
- Helps in Unit testing.
- Boiler plate code is reduced, as initializing of dependencies is done by the injector component.
- Extending the application becomes easier.
- Helps to enable loose coupling, which is important in application programming.
Disadvantages of DI
- It’s a bit complex to learn, and if overused can lead to management issues and other problems.
- Many compile time errors are pushed to run-time.
- Dependency injection frameworks are implemented with reflection or dynamic programming. This can hinder use of IDE automation, such as “find references”, “show call hierarchy” and safe refactoring.
You can implement dependency injection on your own (Pure Vanilla) or use third-party libraries or frameworks.
Libraries and Frameworks that implement DI
- Spring (Java)
- Google Guice (Java)
- Dagger (Java and Android)
- Castle Windsor (.NET)
To learn more about dependency injection, you can check out the below resources:
Java Dependency Injection — DI Design Pattern Example Tutorial — JournalDev
Using dependency injection in Java — Introduction — Tutorial — Vogella
Inversion of Control Containers and the Dependency Injection pattern — Martin Fowler
Hope it helps!
If you liked the article and want to read more amazing articles, then do follow me here (Bhavya Karia) and show your support as it motivates me to write more.
If you have any questions or feedback for me than let’s connect on LinkedIn, Twitter , Facebook.
Thanks to Sergey Ufocoder now this article has been converted into the Russian language. My Russian friends and who all can read the Russian language do give it a read.
If you are a PHP developer then don’t worry, got you all covered as well. Gordon Forsythe recommended this amazing library which you all might want to try out.
Thanks for all the kind words that I have been receiving. Do share the article so that more and more people can be benefited.
If you learnt even a thing or two, please share this story!