Following my last post on Dependency Injection Andy McMullan posted a comment to my Twitter feed:
Just read Fowler's IOC/DI page - seems he disagrees with Prasanna about the superiority of DI over Serv Locator.
In the article Inversion of Control Containers and the Dependency Injection pattern Fowler compares Service Locators and DI and presents some arguments for and against DI compared with Service Locators:
- Easier to determine what dependencies a component has - look at constructor.
- Component does not have dependency on Service Locator so there is not a problem if the component is used with a different framework.
- DI may make testing easier but a good Service Locator mechanism will make stubbing equally feasible
- Harder to debug and understand.
- Component cannot request extra services from injector once it had been configured.
In Concluding Thoughts Fowler says:
… Dependency Injection is a useful alternative to Service Locator. When building application classes the two are roughly equivalent, but I think Service Locator has a slight edge due to its more straightforward behavior. However if you are building classes to be used in multiple applications then Dependency Injection is a better choice.
The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.
In the draft chapter I mentioned in my previous post Dhanji R. Prasanna writes:
Unfortunately, being a kind of factory, service locators suffer from the same problems of testability (or lack thereof) and shared state. The keys used to identify a service are also opaque and can be quite confusing to work with (as anyone who has used JNDI can attest). If a key is bound improperly, then the wrong type of object may be created and this error is found out only at runtime. The practice of embedding information about the service within its key (viz., "JapaneseEmailerWithPhoneAndEmail") is also unclear and places too much emphasis on arbitrary conventions.
I don't think these points are particularly compelling: binding the key incorrectly need not be a concern if, instead of a key string, a type parameter or a generic type parameter is used — for an example see the API of the Common Service Locator library — and the actual type returned from a request to the Service Locator can be configured progammatically or via a configuration file.
But I intuitively prefer the use of DI to a Service Locator. It more clearly separates the two concerns of service configuration and use of the service. It is also potentially more flexible, in that you could have a DI container which could be configured to take into account the class of the component when supplying a particular type in the component's constructor (for example, say the component needed an instance of ILogger and the implementation of ILogger needed to know the type of the component it was going to be logging). In the case where the component needs to request services after its constructor has been called, the component can be supplied with an instance of a provider class.