Jens Schauder is software developer since 1997. He loves software development for the constant challenges and constantly changing environment. A great chance to learn and teach. He is also blogger, author of various articles and speaker at conferences. Jens is a DZone MVB and is not an employee of DZone and has posted 84 posts at DZone. You can read more from them at their website. View Full User Profile

Repeat After Me: Setter Injection is a Symptom of Design Problems

06.14.2012
| 5953 views |
  • submit to reddit

I just stumbled across an article by Steve Schols in which he compares dependency injection via setter with constructor injection. And he prefers setter injection.

I don’t agree. I especially do not agree with his arguments. Lets take them one by one.

What are the problems with constructor injection?
No reconfiguration and re-injection

Why would you want to do that? One reason why many programs are so difficult to think about is that stuff changes around. Think about it. If the state of an object is defined by its constructor you just have to find the place where your object got created in order to understand how it looks like at run time. If the state can be changed through setters you have to find every place where the setter gets called AND if the program control actually came across these places AND in which order in order to understand what state your object is in.

So don’t change the state of your objects.

you could create a circular dependency using Spring. But not by using constructor-based injection

Excuse me? How is this possibly a drawback. I spent a lot of time to fix problems caused by circular dependencies. Using constructor injection prevents many circular dependencies. Absolutely a good thing.

He also quotes the spring reference documentation:

The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy

Again constructor injection shows you you have a problem. I have yet to see a class that has more then three dependencies which adheres to the Single Responsibility Principle.

So if you run into problems with constructor injection congratulation! You just found a strong indication of a design problem in your application. Go ahead fix the design problem and proceed using constructor injection.

Of course there are situations where you can’t fix the design problem and in these cases setter injection is a valid workaround. But it is just that: A workaround.

Published at DZone with permission of Jens Schauder, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Christian Schli... replied on Fri, 2012/06/15 - 12:13am

Nice post!

I found the most important thing about about constructor injection is that it enables immutability. Immutable objects can get easily shared across different threads - just like String. With today's multithreading challenges this is certainly a good thing.

Alessandro Carraro replied on Fri, 2012/06/15 - 12:52am

Agree. Guice too seems to recommend ctor injection. I love the syntax used for field injection, but I perfectly understand why is this BAD, don't blame me, I use it only for toy projects (without unit testing)... ;)

 

Another plus of ctor injection, not noted in your post, is that you cannot use the dependencies in the constructor.. sometime you may want to do some init work in the constructor, but the constructor is called before set & field injection take place, so the fields would be still 'null' when you would need them.

Nice post, very useful 

Lawrence Lorenzo replied on Fri, 2012/06/15 - 4:49am

Although I also always use constructor injection, I do not agree using setters necessarily implicates a design problem.  Sometimes when writing classes for common libraries e.g. it can happen you want to use that class in an IoC container as well as outside it. You may even want to change a field by a setter after creation. So you guys would say this is a design problem and would you rather write an entirely new class just to store that other instance on the fly? What if the specific implementation is only determined at runtime? E.g. after you have first read some settings from a remote site and based on its information you need a specific implementation? What if sometimes you do know the specific info before hand which would allow perfect IoC use? Would you again write two different classes one specific for IoC use and one for outside IoC? That would be ridiculous I think. Sure you could still create argument constructors. In fact, couldn't you always? Instead of calling a dozen setters, having a dozen-argument constructor would work but in the end what the heck are you doing then? I get the point of the author though it is not a golden rule that is always always true. Just my 2cents. Respect to all1 Cheers.

Nate Buwalda replied on Fri, 2012/06/15 - 9:15am

I don't understand all of the FUD and griping around this issue.  Each type of dependency injection has its own purposes.  And each choice comes with consequences.  I don't view one type of injection more or less evil than another.

Constructor injection is great if immutability is your goal and the number of constructors you have on your class is small.  Setter injection is great is you have a large number of properties to set at runtime or if you need to override dependencies and you are comfortable with the mutability caused by it.  Field injection provides a nice medium between the two while making it so only the IoC container knows about the dependency.

Know your tools, pick the best for your situation.  Do not pidgeonhole yourself into the 'my fun is funner than yours' debate. 

 

Andrew McVeigh replied on Fri, 2012/06/15 - 10:27am

Excuse me? How is this possibly a drawback. I spent a lot of time to fix problems caused by circular dependencies. 

Sure, circular dependencies are bad if they are between 2 classes: say, A depends on B depends on A = start of ball of mud.

However, dependencies can easily occur between say an observer and an observed subject, and this is not bad if an interface decouples. For instance, Observer implements IObserver, depends on Subject which depends on IObserver. This type of thing happens frequently in well design software, and cannot easily be managed using constructor dependencies.

Andrew 

Nang Saigon replied on Fri, 2012/06/15 - 11:20am in response to: Nate Buwalda

Agree with Nate Buwalda.

I spent a lot of time to fix problems caused by circular dependencies.

 If this repeats frequently, meaning we don't think much about the design before implementing:).

 Back to the post title.

Setter Injection is a Symptom of Design Problems 

Contructor is used to........create object. If we must add or modify contructor anytime we add new dependency(property,...), just be careful and make sure your contructors don't break the encapsulation principle.

In conclusion,  The frameworks, libraries,... provide us flexible ways to deal with our problems and we should use them in right contexts :)

 

Howard Lewis Ship replied on Fri, 2012/06/15 - 3:46pm

Circular dependencies should not be a problem; they are not an issue in Tapestry IoC. In Tapestry, what gets injected into each service implementation is the lazy-loading proxy for the other service. As long as they don't mutually invoke methods on the other inside the constructor, all will work fine.  I think circular dependencies are a design smell ... you should probably factor things out into a third service, but sometimes it provides the best, or most pragmattic, option.

What I think is important is to have a clean seperation between the service interface and the service implementation; Tapestry strongly encourages you to specify both; only when there's a service interface do you get the full range of features, including lazy loading proxies, non-singleton scopes, and various forms of AOP.

The Spring guys may complain about services that have too many constructor arguments; based on my own experience and feedback from Tapestry users (some of whom use Tapestry IoC seperately from the Tapestry web framework), that's rarely a problem; if any single service has more than a handful of dependencies, it should probably be factored out into multiple collaborating services.  If that's hard in your IoC container, then that's a different issue entirely!

What I think is most important is to build systems that embrace composition rather than inheritance. It is rare in my code for a class to extend another class, rarer still (and the start of a design smell), for there to be more than a single level of inheritance.

Back to the main topic; I prefer constructor injection because it encourages the use of final fields for the dependencies, and ensures that there's no ambiguity about the service's lifecycle: no half-initialized state (unless you do something silly in the constructor, such as path this to some other object). That being said, non-final fields that are written to once, form the constructor, are not going to be a source of runtime errors; nor fields that are injected into directly, via a touch of reflection (though concurrency semantics in the instance after construction are much harder to ensure).

 Generally, when I'm writing framework code for others to use, I use constructor injection into final fields. If I'm putting together an application-specific services, I may use a mix of field injection and constructor injection (Tapestry also supports injection via arbitary methods, including setter methods, though I rarely use those).

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.