Introduction
In general, there are two approaches to implement the Service Locator pattern. The first is like the following:
public class ServiceLocator
{
...
public void AddService(String ServiceName, IService Service){...}
public IService GetService(String ServiceName){...}
}
You can imagine what the client code looks like.
IOrderSvc OrderSvc = (IOrderSvc) ServiceLocator.GetInstance().GetService(ORDER_SVC);
The other approach is like this:
public class ServiceLocator
{
public void addService(String ServiceName, IService Service){...}
public OrderSvc getOrderSvc(){...}
public AccountSvc getAccountSvc(){...}
...
}
Both approaches have their pros and cons. The first approach allows you to add new services easily. The two methods are pretty much it for the ServiceLocator. You create the new service class and call the AddService to add the new service to the locator. But you get the benefit at the expense of type safety. The second approach is exactly the other way around. You have type safety but each time you add a new service, you need to add a new GetXXSvc to the ServiceLocator. As time goes on, the ServiceLocator becomes long and tedious. Is there any way to have the benefits of both approaches?
Generic Methods
The code for the second approach shows a pattern:
public T GetT(){...}
The pattern is exactly what generics are designed for to eliminate the duplication. The following is the new ServiceLocator implementation using generic methods:
public class ServiceFactory
{
...
private Hashtable services = new Hashtable();
public void AddService<T>(T t) where T:IService
{
services.Add(typeof(T), t);
}
public T GetService<T>()
{
return (T)services[typeof(T)];
}
}
Conclusion
No changes to the new ServiceFactory will be needed when adding a new service. We also have type safe checking by compiler when getting a service from this ServiceFactory.
References
History
- 30th September, 2006: Initial post