14

I have a class A that depends on 10 other classes. According to Dependency Injection pattern, i should pass all dependencies of A by its constructor.

So lets assume this constructor (of course this is not a working or real code, since I am not allowed to post the real code here)

public ClassA(ClassB b, ClassC c, ClassD d, ClassE e, ClassF f, ClassG g, ClassH h, ClassI i) {
  this.b = b;
  this.c = c;
  this.d = d;
  this.e = e;
  this.f = f;
  this.g = g;
  this.h = h;
  this.i = i;
}

I have read on Martin Fowler's book about refactoring that having a method with a lot of parameters is a code smell and should not happen.

My question is: is this OK when we are talking about DI? Is there a better way of inject dependencies without breaking Martin Fowler's rules?

I know I could pass the dependencies through properties, but that may cause errors since no one is really sure what should be pass in order that the class works.

EDIT

Thanks for all your answers. I will try now to demonstrate some of class A dependencies:

1 - A class to access a DB
2 - Another class to access another DB (yes, i need to perform operations on two databases)
3 - A class to send error notifications by email
4 - A class to load configurations
5 - A class that will act as timer for some operations (maybe this one can be avoided)
6 - A class with business logic

There any many others that i am trying to get rid of, but those are really necessary and I dont see any ways of avoiding them.

EDIT

After some refactoring now i have 7 dependencies (down from 10). But I have 4 DAO objects:

CustomerDAO
ProcessDAO
ProductsDAO
CatalogDAO

Is it correct do create another class called MyProjectDAO and inject those DAOS onto it? This way I will have only one DAO class that aggregates all DAO objects of my project. I dont think this is a good idea because it violates the Single Responsibility Principle. Am I right?

Rafael Colucci
  • 5,712
  • 4
  • 45
  • 114
  • possible duplicate of [Dependency Injection Constructor Madness](http://stackoverflow.com/questions/2420193/dependency-injection-constructor-madness) – Mark Seemann Mar 13 '12 at 16:24
  • when you use some sort of ORM then all 4 DAOs could be replaced by the UnitOfWork object. – Firo Mar 13 '12 at 17:15

4 Answers4

16

In my experience:

  • Try to design your class so it needs fewer dependencies. If it needs that many, it may have too many responsibilities.
  • If you're really convinced that your class design is appropriate, consider whether it may make sense for some of those dependencies to be joined together (e.g. via an adapter which takes responsibility for one "big" operation your class needs by delegating to a few of the dependencies). You can then depend on the adapter instead of the "smaller" dependencies.
  • If every other bit really makes sense, just swallow the smell of having a lot of parameters. It happens sometimes.
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • In your entire career, have you ever had a situation where a class (or method) really had to take 10 (!) parameters? – Sebastian Weber Mar 13 '12 at 15:31
  • 8
    @SebastianWeber: Absolutely. Professional code is *always* uglier than the carefully-crafted situations which come up in design books :) In some of those cases it was ugly but still appropriate; in other cases it was avoidable and definitely *should* have been avoided; in other cases it was avoidable with a lot of effort, but the effort wasn't worth the benefit. – Jon Skeet Mar 13 '12 at 15:36
  • I see a lot of code that falls into category 2, avoidable and should be avoided. If I ever met a category 3 it was burried underneath a huge pile of more pressing issues so that was the reason for leaving it as is. But I would really love to see a category 1 from a real world system. – Sebastian Weber Mar 13 '12 at 15:44
  • @RafaelColucci: It's hard to say, to be honest - we don't really know enough to say for sure, in particular what interactions are *always* required between your different entities. – Jon Skeet Mar 13 '12 at 18:01
11

Can you justify (to yourself) why the class depends on 10 other classes? Are there member variables you use to tie together a subset of those classes? If so, that indicates that this class should be broken up so that the extracted class would depend on the subset and the variables that tie such state together goes in the extracted class. With 10 dependencies, it's possible that this class has simply grown too large and needs to have its internals broken up anyway.

A note regarding your final sentence: such order dependency can also be a code smell, so it's probably good not to expose it in your interface. In fact, consider whether or not the order requirements are because operations need to be carried out in a specific order (it is the complexity of the algorithm or protocol), or because you've designed your classes to be inter-dependent. If the complexity is due to your design, refactor to eliminate the ordered dependency where possible.

If you cannot refactor (the complexities are all essential and you just have a terrible coordination problem on your hands), then you can abstract the ugliness and keep users of this class shielded (builder, factory, injector, etc).

Edit: Now that I have thought about it, I am not convinced that essential complexities of your algorithm or protocol cannot be abstracted a bit (though that might be the case). Depending on your specific problem, similarities in the manipulations of those dependent classes might either be better solved with the Strategy pattern or the Observer pattern (event listeners). You might have to wrap these classes in classes that adapt them to slightly different interfaces than what they currently expose. You'd have to evaluate the tradeoff of having the code in this monster class become more readable (yay) at the expense of up to 10 more classes in your project (boo).

I'd also like to make an addendum to abstracting the construction of this class. It seems important that any class that depends on this class also use the Dependency Injection pattern. That way, if you do use a builder, factory, injector, etc. you don't accidentally rob yourself of some of the benefits of using the DI pattern (the most important in my mind is the ability to substitute mock objects for testing).

Edit 2 (based on your edit):

My first thought is "what, no logging dependency?" :)

Even knowing what the dependencies are, it's difficult to offer useful advice.

First: what are the responsibilities of everyone? Why does this class depend on controller code (the business logic) and on Model code (two different database access classes, with DAO classes)?

Depending both on DAOs and DB access classes is a code smell. What is the purpose of a DAO? What is the purpose of the DB classes? Are you trying to operate at multiple levels of abstraction?

One of the principles of OO is that data and behavior get bundled into little things called classes. Have you violated this when you created this business logic class distinct from the objects it manipulates distinct from the DAO distinct from this class? Related: Take a brief diversion into SOLID.

Second: A class to load configurations. Smells bad. Dependency Injection helps you identify dependencies and swap them out. Your monster class that depends on certain parameters. These parameters are grouped into this configuration class because...? What is the name of this configuration class? Is it DBparameters? if so, it belongs to the DB object(s), not to this class. Is it generic like Configurations? If so, you've got a mini dependency injector right there (granted, it is probably only injecting string or int values instead of composite data like classes, but why?). Awkward.

Third: The most important lesson I learned from Refactoring was that my code sucked. Not only did my code suck, but there was no single transformation to make it stop sucking. The best I could hope for was to make it suck less. Once I did that, I could make it suck less again. And again. Some design patterns are bad, but they exist to allow your sucky code to transition to less sucky code. So you take your globals and make them singletons. Then you eliminate your singletons. Don't get discouraged because you've just refactored to find that your code still sucks. It sucks less. So, your Configuration loading object may smell, but you might decide that it isn't the smelliest part of your code. In fact, you may find that the effort to "fix" it isn't worth it.

ccoakley
  • 3,125
  • 12
  • 11
  • Even though you did not got many upvotes as others did, I choose to accept you answer because you opened my mind to some things i have not thought about. – Rafael Colucci Mar 13 '12 at 18:49
  • +1 because this is a really helpful (and importantly) generous response. – John Reilly Aug 15 '12 at 10:23
  • And you said a whole lot of stuff without saying anything of substance. Can you please stop wasting everyone's time. – bleepzter Aug 17 '17 at 21:44
3

Yes - a method taking this many parameters should be considered a code smell. Is this method truly only doing one thing and one thing only?

If this is still true you can still lower the number of dependencies by looking at the relationships between the dependencies - are any of them closely related, could they be coupled into aggregate dependencies? E.g. you could refactor by creating a new class K that uses A, B and C internally (injected into class K by constructor, then using composition) - so the number of parameters to the method would be reduced by two.

Rinse and repeat until aggregating doesn't make sense anymore and/or you have a reasonable number of parameters.

Also see a related blog post: "Refactoring to Aggregate Services"

BrokenGlass
  • 149,257
  • 27
  • 271
  • 318
-2

I'd also advise to redesign your application. In case it is not possible you can pass your IoC container as a constructor parameter. If you do not want to couple your code with a concrete implementation you can always abstract it. The code will look something like this.

public interface IAbstractContainer
{
  T Resolve<T>();
}

public class ConcreteContainer: IAbstractContainer
{
  private IContainer _container; // E.g. Autofac container

  public ConcreteContainer(IContainer container)
  {
    _container = container;
  {

  public T Resolve<T>()
  {
    return _container.Resolve<T>();
  }
}

public classA(IAbstractContainer container)
{
  this.B = container.Resolve<ClassB>();
  this.C = container.Resolve<ClassC>();
  ...
}

}

A ConcreteContainer instance is injected the usual way.

Dmitriy Melnik
  • 520
  • 1
  • 4
  • 12
  • 5
    this doesn't solve the problem, all this does is "hide" the dependencies since you are not using constructor injection anymore, furthermore you have a new dependency to the container - this is in fact not IoC but Service Locator pattern – BrokenGlass Mar 13 '12 at 15:23
  • 5
    Using a service locator is not a good idea as one of the (many) benefits of DI is that you have some idea of what the object's dependencies are. – Ritch Melton Mar 13 '12 at 15:27
  • 5
    Thanks. I've got to understand it now. My answer will serve as an illustration of this anti-pattern so that others could avoid using it. – Dmitriy Melnik Mar 14 '12 at 09:29