I wrote this post in December of 2009 but since it is quite popular I decided to migrate it to my current blog.
I had a conversation over the weekend with one of my colleagues because I didn’t understand the difference between an Inversion of Control (IoC) container and a Service Locator. After our twitter conversation, I had to go back and read the article by Martin Fowler on the topic. Although the article is dated, it provides some valuable information. That information along with my colleague’s information clarified the difference.
The confusion was mostly because both tools provide similar services, both provide run-time resolution of dependencies. Also when improperly used, an IoC container can be used in the same fashion as a Service Locator can- as was the case in one of my former projects.
Before I get going too far, let me explain what I mean when I say “run time resolution of dependencies”. In order to write testable code in OO we have to write classes that are loosely coupled. No coupling at all would be optimal (for testability), but as any programmer knows, that is just not possible At some point a class is going to depend on another class. This other class may have dependencies on resources that are not available during test execution.
So how do we get around this? The answer is by coding against abstractions. In C# we use normally interfaces (preferably over abstract classes), in other languages that may be abstract classes. In other words, we code against a contract. The dependent class does not need to know about the implementation details, only the contract. That is to say if we provide the class this set of parameters it will provide us the agreed result. As my former project lead liked to say “It’s a black box, you put in corn and out comes cornflakes. How the cornflakes are made is irrelevant to the user”.
Ok, so now our dependent class has an abstraction, big deal, at some point, the real object will have to be created and you simply can’t instantiate an interface or an abstract class. Therefore, at some point, we will have to call new on the concrete class that implements the abstraction. That’s where either the Service Locator or IoC tool comes in. The Service Locator can be thought of as a container itself, after all, it does contain the information (or possibly the instance) to create the concrete class. The IoC container can also be used the same way as a Service Locator, when improperly used.
The Service Locator would be called something like the following:
IMyType myObject = (IMyType)myServiceLocator.GetService(typeof(IMyType));
Where we would pass in the type of the interface and it would return the concrete class. (Ignore the fact that I am not using generics, I didn’t want to get too wrapped in the semantics. If you have the capability to use generics please do so.) This type of code would be sprinkled throughout our code. We need a service here or there? We just call the Service Locator and request it. Keep in mind that we could use the IoC tool of our choice the same way, but if that is all we are using an IoC tool for, we are seriously under-utilizing it.
The IoC tool, on the other hand, may be called in the following manner:
IMyType myObject = (IMyTYpe)SomeIoCTool.Resolve(typeof(IMyTYpe));
Wait a minute! what’s the difference?! Well from those two lines nothing, except for the variable and method names, which are fictional, to begin with (Please refer to your tool of choice for the semantics of the tool). The real difference is that with an IoC tool you have dependency injection capabilities. This means that, for example, if your concrete object has a parameterized constructor, the dependencies will be injected by the IoC tool. The IoC tool may also have the capability to inject dependencies on properties and methods. The Service Locator will only work with the default parameterless constructor and does not have the capability to perform dependency injections. This also means that if you have a hierarchical object where the object has children and they have grand-children and they have little great-grandchildren… well you get the picture. And those descendants have dependencies as well, they will also be injected with the appropriate dependencies. The IoC tool has the capability to build the entire object graph from the abstractions.
There are many more features that IoC tools possess, but for the purpose of this article the features mentioned are sufficient.
In case you are wondering how the internal workings of either tool allow them to resolve dependencies, the answer to that question can be summed up in two words: registration and reflection. Somewhere in the entry point to our process we told the Service Locator or IoC container to provide us with a particular concrete class whenever we asked for a particular interface. It would look something like the following:
There is of course more to the Service Locator and the IoC container, but for the most part, this is the basic concept.
In summary, the main difference between a Service Locator is that the Service Locator will be sprinkled throughout the code where needed, the sprinkling is mostly because it cannot perform dependency injection. Well actually it can but the item that needs it may not be setup or registered in the IOC.
The IoC tool will usually not be sprinkled throughout the code. Since it has the capability to perform dependency injections, it can build the entire object graph from scratch. Also, for this reason, it can resolve dependencies earlier in the process that the Service Locator can.
The Service Locator can be something as simple as a class with a hashtable that maps the interface type and the concrete type. Using reflection, it can construct the appropriate type at run time. Why is important to create the type at run time. Well because we need the capability to swap it out during our tests so that our test can concentrate on the logic. The IoC tool is way more feature rich and is usually a third party tool that can; construct an object with all dependencies, build up an object’s dependencies after construction, perform Aspect Oriented Programming (AOP) capabilities and so on and so forth.
And if you think you got it please note that a Service Locator may use an IOC under the hood and in essence all the service locator is, is a global object that can be used to resolve dependencies.
If you are interested in learning more about IoC tools please visit the following links.