- summary Introduction to dependency injection.
Dependency injection is a technique for supplying external dependencies to a component. Why do we need it?
Imagine, we have a class which has an engine, a body, and wheels.
Even though there is no problem with the class above, it is difficult to test or extend it, because all its dependencies are _hard-coded_. A better way is to explicitly specify its dependencies, so that they can be overridden.
Now it is possible to test the class using fake objects:
Or to extend it with another parts:
- Do not hard-code dependenies.*
There is still one problem with the code above, though it is not evident from the class. It is the problem of instantiating and reusing objects. Imagine we are building a web application (MVC). In it some classes need to be instantiated once for each request, others -- once for the whole application.
The application requires one database pool, reused across all its thread. It can be implemented as a thread-safe singleton and accessed directly.
It is possible to test , but it is impossible to supply a new pool for the whole application without overriding the attribute in every model. It is possible to create a factory, which will return a pool, but the factory instance will still be hard-coded in each model.
One model in the application requires a session, a logger, and an emailer, and all these objects have to be request-local (one instance per request). For example, they are user-specific. The usual way to supply these requirements is to store them in the request object, and then pass them to the model via a controller.
_But this is a functional way of doing things!_ has no business logic now; it serves as a dependencies resolver for a model. Every time model's requirements change, the controller has to be changed too.
- A better way of reusing objects is required.*
Dependency injection tackles all the specified problem.
has a dependency for a database pool. So is injected into it.
Then an injector is configured to supply one instance for the whole application.
It is possible to supply another class, for example:
, , and are injected directly into model's function, and are instantiated with the request scope.
Also, it would be better to get rid of model's class methods, move them into class and inject it into the controller.
Dependency injection provides:
* Loose-coupling for components.
* Instantiating and reusing objects according to their scopes.
* Testability.
* Flexible configuration.