A quick intro to Dependency Injection: what it is, and when to use it
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
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 statistically but should be configured by some other class from outside.
It is the fifth principle of S.O.L.I.D — thefive 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
To learn more about dependency injection, you can check out the below resources:
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.
Edit:
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.
Also, if you want to apply DI in JavaScript and are looking for a library then Jo Surikat suggests that you give a try to his library.