Understanding what dependency injection is outside of angular (DI onwards in the article) will help us gain a broader perspective of how it works and provide us knowledge on why it is important and how to leverage it inside angular, so the first question is:
DI is in fact a programming design pattern in object oriented languages that allows classes to use dependencies without needing to know anything about them. It aims at a greater separation of concerns, decoupling the link between client class and the dependency.
For instance, normally in an OOP language such as Typescript one would pass dependencies the following way:
Basically the class (client) would need to instantiate the new object (service) with the keyword new with all the properties the new object constructor would need, so the service is hard coded inside the client, creating a tighter coupling between the two classes.
However using DI the dependency the client does not build the service itself, it only needs to declare the interfaces of the services it uses
The heavy lifting in DI is done by an object called injector who is the responsible to provide the new object to the receiving class and keep track of the object graph and each objects implementations.
This pattern allows for greater modularity and code reusability since each class worries only of itself and not so much about how its dependencies are constructed
Since we know that in angular we aim to create code that is very reusable and modular it makes total sense that the angular team opted in for this design pattern as it supports this vision of modular and reusable components code.
Angular also uses injectors to provide the dependencies, actually the
providedIn:'root' that we normally see in services is referencing to the root injector, which takes care of dependencies that need to be available in the whole application.
We'll see more about that in the next chapters of this series about dependency injection. For now a small recap:
- Dependency injection is a design pattern that aims to have greater code reusability and modularity
- There are 3 main actors in this design: Client, Service and Injector
- The design fits perfectly in angular where client, service and injector are integrated within the framework in order to enhance the modularisation and reusability of its elements (services, components, directives and pipes)