John Munsch explains it like this:
When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.
What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.
In designing an object-oriented application, a major tenet of design is “loose coupling”. Objects should only have as many dependencies as is needed to do their job – and the dependencies should be few.
There are three primary approaches to implementing DI:
- Constructor injection
- Setter injection (also called Property injection)
- Method injection
Constructor injection uses parameters to inject dependencies. In setter injection, you use setter methods to inject the object’s dependencies. Finally, in interface-based injection, you design an interface to inject dependencies.
Example of Tightly Bound Classes
In the following example, your
Client class needs to use a
Service class component. So it tightly binds with the
But when it does that, you cannot use a different implementation of your
Client class. The following will not compile.
This diagram shows how they are tightly bound. Arrows represent that the Program calls the Client and the Service directly.
Example of Constructor Injection
Constructor Injection is the most common DI.
Dependency Injection is done by supplying the DEPENDENCY through the class’s constructor when instantiating that class.
Injected component can be used anywhere within the class.
Should be used when the injected dependency is required for the class to function.
It addresses the most common scenario where a class requires one or more dependencies.
Sample of Construction Injection
In this case, your
Client class needs to use a
Service class component, you can make your
Client class aware of an
IService interface rather than a
Service class. In this way, you can change the implementation of the
Service class at any time (and for how many times you want) without breaking the host code.
The dependency diagram shows that the Client is no longer tightly bound to a particular service.
You can now use a Test Client with a different implementation of IService. In this case, you can call it AlternativeService.
Either the test program or the client can choose the implementation of IService at runtime.
Property injection is also called Setter injection.
Used when a class has optional dependencies, or where the implementations may need to be swapped. Different logger implementations could be used this way.
May require checking for a provided implementation throughout the class(need to check for null before using it).
Does not require adding or modifying constructors
Property Injection Sample Code
The following is an example showing property injection.
Method injection injects the dependency into a single method, for use by that method.
Method injection can be useful where the whole class does not need the dependency, just the one method.
Method Injection Sample Code
Method injection is generally uncommon, usually used for edge cases. The following is a sample:
Here are some key take aways:
- Reduces class coupling
- Increases code reusing
- Improves code maintainability
- Improves application testing
Sample code for this post is available in the Patterns folder of the DevDays repository on GitHub.
Special thanks to Shailendra Chauhan for the post on Implementation of Dependency Injection Pattern in C#.