Recently, a young programmer told me I should use constructor injection. I asked how so, and he said
“That’s better. That is how it should be done”.
When you google the subject, you find three reasons people give for constructor injection.
- The single responsibility violation. If you see a constructor with many parameters, you know your class has many responsibilities, or “is doing too much”.
- Hidden dependencies: classes injected by field injection don’t show up in the API documentation.
- Constructor injection makes your classes container agnostic.
I think 1 is a bit far fetched. Having 12 injected classes in your constructor looks ugly, but so does 12 classes with field injection.
2 makes sense. On the other hand, not all classes do need to show up in the documentation. In OOP, the documentation should provide details on how to use the class, not how it’s implemented. Classes should hide implementation details, not expose them via the API documentation.
Your classes being container agnostic is a good argument. Field injection ties your classes to the specific container you are using, which I think is not desirable. I like to use an applicationContext.xml file to specify all implementations to be injected. If everything is in the xml file and in constructors, your code is pretty much container agnostic.
The same young programmer had asked me before why I use interfaces. “In Spring Boot, you don’t have to use interfaces”. He also disliked my applicationContext.xml, he used @Component annotations and Componentscan for specifying Beans. Which imho totally defeats the idea of making your code container agnostic by using constructor injection. In a large project, using @Component injection can make it hard to find all beans, there’s no list of them. Not using interfaces puts a dependency on your specific container in the implementation class.
My advice would be to take either one of the following approaches.
You use constructor injection, you use interfaces wherever applicable, you use an applicationContext.xml file for configuration. Or, instead of applicationContext.xml, you use @Configuration classes for configurations.
If you don’t do all these, then you may as well do none of them. Not using interfaces or using @Component injection violates container independency, so why not use field injection and no interfaces either. I like field injection because it makes your code more concise and more readable.
The pragmatic way would be to try to be container agnostic for some dependencies but not for others. Dependencies that are purely implementation detail, you can hide by using field injection and @Component annotations. Things like DAO classes, you don’t want to hide, so you define them in interfaces and configure injection in one place, not in the DAO class itself.
Whichever approach you take, make sure to give it thought and discuss it in your team.