Service Locator vs. Dependency Injection
Posted by Nicholas Blumhardt | July 08, 2007 16:40
Something I have come back to a few times when explaining the benefits of Dependency Injection is how the pattern relates to Service Locator. Martin Fowler thinks Service Locator is a better choice when you’re building a single application, while Dependency Injection can be more appropriate otherwise.
You can get a good idea of how the two patterns work by reading his article. I don’t agree with his conclusion, in part because when setting out to build an application you often end up building a small suite of related apps: the main front-end you always intended to write, perhaps some administrative tools, perhaps some data import tools, perhaps some back-end services that run on a schedule. Once this happens, Dependency Injection beats Service Locator hands-down.
The oft-quoted drawback of Service Locator is that all the components depend on the locator. To me this isn’t a big deal. The problem dependency that Service Locator introduces is a much larger-scale one - the components, through the keys that they use to locate associated services, create an implied system architecture that is hard to change from outside the components themselves.
For a simple example, let’s say the Authenticator component and the Auditor component both look up the service “logger”. By using the simple key “logger” in both cases, these components implicitly depend on the same object. In a different environment, we may require the the Auditor logs to the database, and the Authenticator logs by sending email to an administrator. Using a service locator we have a couple of choices:
- Use a different scheme for the keys, e.g. “logger/authenticator” and “logger/auditor” - now our ’simple’ service locator is getting more complex and we have to sort out in advance how our service naming scheme works.
- Build the flexibility into the logger - use different log sinks for different sources. This isn’t a bad option, but is essentially a case of moving general functionality out of our architecture into specific functionality within the components, thus adding more complexity to the system.
- Change the Authenticator and Auditor so that they can be initialised with a specific logger when the application starts up.
To me, option number 3 is the common-sense choice: after all, it makes use of the most basic features of the programming language we’re working in and saves us from creating our own more complex structures on top of the language.
Coincidentally :) option number 3 is Dependency Injection. By having all of our components accept their dependencies as constructor or property arguments, they can be wired up in arbitrary ways without any need for code changes.
That’s really as far as you have to take dependency injection - and while the application is small, your startup code can just create and wire up components as needed. Beats Service Locator for the simple fact that you’re sticking to the built-in dependency mechanisms of your programming language, and later on, if you want to use a dependency injection framework to simplify the configuration code, you can do so without changing your components.
Disclaimer: These articles represent the opinions of the authors and may not match the official position of Ubik Systems Pty. Ltd. Confirmation should be sought on all matters involving professional advice.
