Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with constructor over-injection in .NET

I'm sorry if that question was already discussed, but I didn't find exactely what I wanted. The problem I'm facing is more about patterns and design choices than about .NET itself. I just would like to have your advice to know where to start my refactorings.

Today I opend one of the classes in my actual application and found that it has 13 dependencies injected by constructor !!! In fact each developper added the dependecy it needed in method that he was writing.

One point of my understanding of DI is that when we inject a dependency by constructor it means that it's a mandatory dependency and should be used in all methods of the class. If we need a particular dependency just in one method of the given class, what does it mean for you ?

  • The given class does too much ? I should consider to create a new type just with a needed dependency ?
  • I should inject by property ? But in that particular method a dependency is mandatory so I don't think it's a good choice.
  • I should inject by method ?

What's difficult is to find the right balance. In reallity sometimes it's not possible to encapsulate the bahaviour in the clean way.

I was considering to create something like service aggregator to hind related dependency behind one of them but would like if you have other advices. Thanks in advance.

like image 431
Tomasz Jaskuλa Avatar asked Jan 05 '11 11:01

Tomasz Jaskuλa


People also ask

Is it difficult to inject dependency by constructor?

Frameworks that apply the Constrained Construction anti-pattern can make using Constructor Injection difficult. The main disadvantage to Constructor Injection is that if the class you're building is called by your current application framework, you might need to customize that framework to support it.

Which injection is better setter or constructor?

Setter Injection has upper hand over Constructor Injection in terms of readability. Since for configuring Spring we use XML files, readability is a much bigger concern.

Does @inject call constructor?

@Inject can apply to at most one constructor per class. @Inject is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.


2 Answers

You are correct: if you need to inject 13 dependencies into a class, it's a pretty sure sign that you are violating the Single Responsibility Principle. Switching to Property Injection will not help, as it will not decrease the number of dependencies - it will only imply that those dependencies are optional instead of mandatory.

Basically, there are two ways to deal with this type of problem:

  • Refactor to Facade Services. This is basically a non-breaking refactoring as it maintains the functionality of the Controller. However, it changes the responsibility toward coordinating/orchestrating the interaction between services instead of managing the nitty-gritty details of the implementation.
  • Split up the class into independent classes. If each of the services were introduced by different developers to support a subset of the methods, it's a sign of low cohesion. In this case, it would be better to split up the class into several independent classes.

Specifically for ASP.NET MVC you may not want to split up an Controller because it will change your URL scheme. That's fair enough, but consider what this implies: it means that the single responsibility of the Controller should be to map URLs to application code. In other words, that's all a Controller should do, and it then follows that the correct solution is to refactor to Facade Services.

like image 66
Mark Seemann Avatar answered Oct 04 '22 01:10

Mark Seemann


Just because a dependency is mandatory doesn't mean it should be used in all the methods of a class, IMO. It should just be logically part of the configuration of the class itself.

On the other hand, if a class has 13 dependencies it may well be doing too much. Do any of those dependencies logically belong together? Perhaps the dependencies themselves should be "chunkier" - or quite possibly your class should do less.

like image 26
Jon Skeet Avatar answered Oct 03 '22 23:10

Jon Skeet