Are we using DI correctly?
Dependency Injection, the right way!
What is DI?
Technically, Dependency injection is a programming technique that makes a class independent of its dependencies.
Duh..!!!
Yes, I understand, I also hate such definitions. Let’s talk informally from now on.
The concept of dependency injection says, One particular class or implementation should not be worried about the change in the implementation of a nested logic.
The changing logic should be kept separate from the original class so that if any of the business rules or underneath logic changes, it should not require a change in the original class or implementation.
The original class or implementation should only be dependent on the final outcome or result of the dependent class and not on how the outcome was implemented.
Types
Since now you know what Dependency Injection is and why did it pop out, We will look at how can we actually inject our dependencies in code.
There are three ways of doing this,
- Property-based :
A property-based DI means directly autowiring the dependency while declaring the variable. This is not-at-all testable as this means you don’t have any way to actually initialise in case of unit-testing. Below is the (most evil) code,
class Package {
@Autowired
private Device mobile; @Autowired
private Charger charger;}
- Setter-based :
A setter-based DI means autowiring the dependency using the setter of the variable. Below is the code,
class Package {
private Device mobile;
private Charger charger; @Autowired
public void setDevide(Device mobile) {
this.mobile = mobile;
} @Autowired
public void setCharger(Charger charger) {
this.charger = charger;
}}
- Constructor-based :
A constructor-based DI means autowiring the dependency only when the actual Object/Bean creation is done. This is more intuitive and testable. Below is the code,
class Package {
private Device mobile;
private Charger charger; @Autowired
public Package(Device mobile, Charger charger) {
this.mobile = mobile;
this.charger = charger;
}}
Why prefer Constructor-based DI?
When you closely look at what Dependency Injection via constructors say you find it intuitive and the correct thing to do.
Constructor-based DI says, pass all the dependencies for the given class to my constructor. This means if one does not provide all the dependencies, object creation will not take place.
One might argue, we can always pass the dependencies as null
and create the desired object. Yes, this is true, one can do this but passing null
for resolving a dependency cannot be counted as a mistake or unintentional.
If someone does this, he/she will be fully aware of the consequences (one being the NullPointerException
).
If we consider an informal view of this, constructor-based DI says if you want to manufacture a new
Handset (object), the manufacturer (developer) needs to keep the Mobile set (dependency 1), a Mobile charger (dependency 2), usage handbook (dependency 3) at the same time and then pack it for sale.
In the case of the other two, this is not the case and the manufacturer has high chances of missing something in the packing which might lead to a poor review on Flipkart or AmazonEcommerc.
Spring IoC
Spring framework’s Inversion of Control is nothing but handling of the dependencies in your source code.
Spring came out with IoC and said Developers should not be concerned with Object creation (which was already taken care of by JVM at one level and now this!) but only the business logic and rules.
IoC underneath uses the principle of Dependency Injection for creation of Objects that can be used by developers without worrying about managing the memory.
So, now developers are only left with @Autowired
and @Inject
This is something I really feel bad about.
Leaving with a quote from someone truly passionate about changing the world, which every developer wants to.
“You can build your own things that other people can use. And once you learn that, you’ll never be the same again.”