thanx for your exhaustive response!
I'll need some time to test all the implications of the above points in my own solution...
For the moment I'll try with the last option, injecting the IServiceLocator as a dependency, and I'll see how it fits.
QUESTION: do u know of any implications in propagating this single dependency down to child view models with Catel?
Indeed I personally think that the ServiceLocator pattern used without knowing its risks IS an anti-pattern...
My primary concern is the testability of the classes that uses the ServiceLocator pattern, and I think this is the main concern that causes so many people calling it an "anti-pattern".
For example, if I use the ServiceLocator in a method to locate and instantiate a service with some interface, and I simply use it and then dispose it, I'm hiding this dependency in my internal implementation. Imagine doing this in hundreds classes and with
There isn't an explicit contract between my class and the external world, so how can u assure your testing coverage? The answer is: you have to constantly read all the source code of the class to gather all the dependencies it has!
MEF and Unity, on the other hand, gives you the opportunity to move the construction of the dependency graph in a single location (for WPF at startup), so it's not an anti pattern at all! In fact you didn't have to go through ALL your classes to see which
are the dependencies, 'cause you have a single place to look at, and your testing experience will benefit from this...
So I think that Constructor injection is the simplest and the clearest solution to do DI.. A clear contract between your classes and the rest of the world.
As for the child view model issues, an option could be not using them at all, like in other frameworks. A single view model is responsible for all its child views.
But maybe you'll find a workable solution in the future to propagate dependencies down to children in a semi automatic way (for example using some sort of attributes on the parent class to tag the dependencies that needs to propagate down).
In conclusion, I think that, in a TDD world, you have to stay away from solutions that hides the full set of responsibilities of a class!
Another bad example are loose messaging systems, when a view model can send arbitrary messages out in the space, and other view models register to receive them.. how do u think your test experience will be?
A simple and workable solution here is to EXPLICITLY implement an interface on the receiver that declares all the messages entry points as methods (methods ARE messages, aren't they?)
During runtime you continue to use the messaging system, BUT in your tests you mock out the messenger service and simply use the plain old methods to send messages to your view models...
I'm sorry for the length of this post, but I hope that this clarifies the whole point of ServiceLocator detractors! ;)