Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

When designing a system I am often faced with the problem of having a bunch of modules (logging, database acces, etc) being used by the other modules. The question is, how do I go about providing these components to other components. Two answers seem possible dependency injection or using the factory pattern. However both seem wrong:

  • Factories make testing a pain and don't allow easy swapping of implementations. They also don't make dependencies apparent (e.g. you're examining a method, oblivious to the fact that it calls a method that calls a method that calls a method that uses a database).
  • Dependecy injection massively swells constructor argument lists and it smears some aspects all over your code. Typical situation is where constructors of more than half classes look like this (....., LoggingProvider l, DbSessionProvider db, ExceptionFactory d, UserSession sess, Descriptions d)

Here's a typical situation I have a problem with: I have exception classes, which use error descriptions loaded from the database, using a query which has parameter of user language setting, which is in user session object. So to create a new Exception I need a description, which requires a database session and the user session. So I'm doomed to dragging all these objects across all my methods just in case I might need to throw an exception.

How do I tackle such a problem??

share|improve this question
    
If a factory can solve all your problems, maybe you could just inject the factory into your objects and get LoggingProvider, DbSessionProvider, ExceptionFactory, UserSession from that. –  Giorgio Mar 11 '13 at 13:49
1  
Too many "Inputs" to a method, be they passed or injected, is more a problem of the methods design itself. Whichever you go with you might want to reduce the size of your methods a bit (which is easier to do once you get injection in place) –  Bill K Mar 11 '13 at 19:47
add comment

6 Answers

up vote 33 down vote accepted

Use dependency injection, but whenever your constructor argument lists become too big, refactor it using a Facade Service. The idea is to group some of the constructor arguments together, introducing a new abstraction.

For example, you could introduce a new type SessionEnvironment encapsulating a DBSessionProvider, the UserSession and the loaded Descriptions. To know which abstractions make sense most, however, one has to know the details of your program.

A similar question was already asked here on SO.

share|improve this answer
5  
+1: I think grouping constructor arguments into classes is a very good idea. It also forces you to organize these argument into more meaning structures. –  Giorgio Mar 11 '13 at 13:51
1  
But if the result is not a meaningful structures then you are just hidding complexity that violates SRP. In this case a class refactoring should be done. –  danip Sep 15 '13 at 13:22
add comment

Dependecy injection massively swells constructor argument lists and it smears some aspects all over your code.

From that, it doesn't seem like you understand DI proper - the idea is to invert the object instantiation pattern inside of a factory.

Your specific problem seems to be a more general OOP problem. Why can't the objects just throw normal, non-human-readable exceptions during their runtime, and then have something before the final try/catch that catches that exception, and at that point uses the session information to throw a new, prettier exception?

Another approach would be to have an exception factory, which is passed to the objects through their constructors. Instead of throwing a new exception, the class can throw on a method of the factory (e.g. throw PrettyExceptionFactory.createException(data).

Keep in mind that your objects, apart from your factory objects, should never use the new operator. Exceptions are generally the one special case, but in your case they might be an exception!

share|improve this answer
1  
I have read somewhere that when your parameter list gets too long it is not because you are using dependency injection but because you need more dependency injection. –  Giorgio Mar 11 '13 at 13:52
    
That could be one of the reasons - generally, depending on the language, your constructor should have no more than 6-8 arguments, and no more than 3-4 of those should be objects themselves, unless the specific pattern (like the Builder pattern) dictates it. If you're passing parameters to your constructor because your object instantiates other objects, that's a clear case for IoC. –  Jonathan Rich Mar 11 '13 at 13:55
add comment

You have already listed the disadvantages of the static factory pattern quite well, but I don't quite agree with the disadvantages of the dependency injection pattern:

That dependency injection requires you to write code for each dependency is a not a bug, but a feature: It forces you to think about whether you really need these dependencies, thereby promoting loose coupling. In your example:

Here's a typical situation I have a problem with: I have exception classes, which use error descriptions loaded from the database, using a query which has parameter of user language setting, which is in user session object. So to create a new Exception I need a description, which requires a database session and the user session. So I'm doomed to dragging all these objects across all my methods just in case I might need to throw an exception.

No, you're not doomed. Why is it the responsibility of the business logic to localize your error messages for a particular user session? What if, sometime in the future, you wanted to use that business service from a batch program (which doesn't have a user session ...)? Or what if the error message should not be shown to the currently logged in user, but his supervisor (who may prefer a different language)? Or what if you wanted to reuse business logic on the client (which doesn't have access to a database ...)?

Clearly, localizing messages depends on who looks at these messages, i.e. it is the responsibility of the presentation layer. Therefore, I'd throw ordinary exceptions from the business service, that happen to carry a message identifier that can then be looked up the presentation layer's exception handler in whatever message source it happens to use.

That way, you can remove 3 unnecessary dependencies (UserSession, ExceptionFactory, and probably descriptions), thereby making your code both simpler and more versatile.

Generally speaking, I'd only use static factories for things you need ubiquitous access to, and that are guaranteed to be available in all environments we could ever want to run the code (such as Logging). For everything else, I'd use plain old dependency injection.

share|improve this answer
add comment

Use dependency injection. Using static factories is an employment of the Service Locator antipattern. See the seminal work from Martin Fowler here - http://martinfowler.com/articles/injection.html

If your constructor arguments become too large and you're not using a DI container by all means write your own factories for instantiation, allowing it to be configurable, either by XML or binding an implementation to an interface.

share|improve this answer
2  
Service Locator is not an antipattern - Fowler himself references it in the URL you posted. While the Service Locator pattern can be abused (in the same way that Singletons are abused - to abstract away global state), it is a very useful pattern. –  Jonathan Rich Mar 11 '13 at 13:37
    
Interesting to know. I've always heard it referred to as an anti pattern. –  Sam Mar 11 '13 at 13:45
3  
It's only an antipattern if the service locator is used to store global state. The service locator should be a stateless object after instantiation, and preferably immutable. –  Jonathan Rich Mar 11 '13 at 13:57
add comment

I would go as well with Dependency Injection. Remember that DI is not only done through constructors, but also through Property setters. For example, the logger could be injected as a property.

Also, you may want to use an IoC container that may lift some of the burden for you, for example by keeping the constructor parameters to things that are needed at runtime by your domain logic (keeping the constructor in a way that reveals the intention of the class and the real domain dependencies) and maybe inject other helper classes through properties.

A step further you may want to go is Aspect-Oriented Programmnig, which is implemented in many major frameworks. This can allow you to intercept (or "advise" to use AspectJ terminology) the constructor of the class and inject the relevant properties, maybe given a special attribute.

share|improve this answer
    
I avoid DI through setters because it introduces a window of time during which the object is not in fully initialized state (between constructor and setter call). Or in other words it introduces a method call order (must call X before Y) which I avoid if at all possible. –  U Mad Jan 10 at 13:05
    
DI through property setters is ideal for optional dependencies. Logging is a good example. If you need logging, then set the Logger property, if not, then don't set it. –  Preston Feb 19 at 17:58
add comment

This comparison between dependency injection and service locator may help you.

Also, sometimes it's OK to have a global singleton, as the (surely configurable) logging service example in this article (see the section When it really is a singleton).

share|improve this answer
    
Answers which just contain links are considered bad practice. Please summarize the content here (don't copy/paste) so the answer can stand on its own. If you don't you run the risk of your answer being removed, especially if the link ever dies. –  Martijn Pieters Feb 19 at 13:56
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.