views:

132

answers:

2

I've been reading through Misko Hevery's Guide: Writing Testable Code.

I definitely buy into dependency injection as a great tool to improve testability, and use it a lot in my code. However, when reading the first part of the guide "Flaw #1: Constructor does Real Work", I find I'm still a bit fuzzy on how you're supposed wire up event listeners.

Let's say I have a class, which, in order to work properly, needs to attach a listener to one of the arguments that's passed in via constructor dependency injection. According to the guide, the constructor should only assign it's arguments to member variables, and do no other work. In addition, the object should be fully initialized when the constructor finishes. However, in this case, I wouldn't consider the object to be fully initialized unless it's required listeners are hooked up.

As far as I can tell, this requires hooking up all the listeners in the builder or factory, though this seems very decoupled from the object itself, and easy to get out of sync. In addition (at least in actionscript, which I'm spending most of my time in these days), this would mean that my event listeners could no longer be private, since the factory/builder would need to see them.

What's the best way to handle this? Is there another option I'm missing here?

+1  A: 

Separate the business logic (call graph) from object creation

Specifically: If House requires an initialized Kitchen in order to function correctly, an initialized Kitchen should be passed into the House constructor.

House should not be responsible for initializing Kitchen. That is someone else's responsibility. (Probably whoever built the Kitchen in the first place.)

However, there is a small gotcha: If the object has a shorter lifetime than House, it does not belong as a member variable. For example: Person or Owner probably shouldn't be be passed in via the constructor. It should be passed in via function calls.

Misko's latest article on managing object lifetimes talks about this subject.

Runcible
+1  A: 

A common pattern is to move the wiring into an initialize() or start() method, and take advantage of your dependency injection container's lifecycle mechanism to ensure the method gets called.

On my current project, we combine annotations with Spring and Spring.NET's bean postprocessors to wire up event listeners to methods.

Ajit George