A Service Locator is a common design pattern that allows decoupling clients of services (described by a public interface) from the concrete class implementing those services. Martin Fowler has a great introduction on the topic in his Inversion of Control Containers and the Dependency Injection pattern.
What follows is a very simple service locator implementation in C# based on generics.
Let’s start defining the contract of a service locator.
public interface IServiceLocator
{
T GetService<T>();
}
Now let’s see a very simple implementation of this contract:
class ServiceLocator : IServiceLocator { // map that contains pairs of interfaces and // references to concrete implementations private IDictionary<object, object> services; internal ServiceLocator() { services = new Dictionary<object, object>(); // fill the map this.services.Add(typeof(IServiceA), new ServiceA()); this.services.Add(typeof(IServiceB), new ServiceB()); this.services.Add(typeof(IServiceC), new ServiceC()); } public T GetService<T>() { try { return (T)services[typeof(T)]; } catch (KeyNotFoundException) { throw new ApplicationException("The requested service is not registered"); } } }
As you can see,
IServiceA
, IServiceB
, and IServiceC
. It is assumed here that ServiceA
implements IServiceA
and so forth. This is how a client would invoke the service:
IServiceLocator locator = new ServiceLocator();
IServiceA myServiceA = locator.GetService<IServiceA>();
The clients do not know the actual classes implementing the service. They only have to interact with the service locator to get to an implementation.
This is as simple as it gets. There are several improvements that a real-world implementation of a service locator should consider (what follows is only a partial list):
Next article in the series: Service Locator Pattern in C# with Lazy Initialization