Introduction
There are many articles on the net that provides information about Service Locator pattern. This article expresses my view of Service Locator pattern.
The basic idea of pattern is to decouple service Consumers from their Providers. It allows a Consumer to easily change its service Provider. It's one of the patterns used for applying Dependency Inversion Principle (DIP) in your application.
The example project gives the simplest way of implementing pattern in your application.
Background
The Service Locator pattern is used for applying Dependency Inversion Principle (DIP) in your application. The DIP states "A High level module in an application must not be directly dependent on Low level module, but must rely on abstraction". This allows modules to change their implementation without effecting each other providing loose coupling and easy extension.
I have noticed many articles in web place Service Locator directly under Inversion of Control (IoC), I strongly believe that it's not so. IoC governs how control flows in your application. In a non-complaint IoC application, our application waits for some input from keyboard or mouse and executes business logic and again gets back waiting for user input, where as a complaint IoC application written using frameworks like WPF, WCF or WinForms requires us to hook our business logic to framework access points to execute. So code written by developer is not directly controlling the control flow of an application, to apply IoC a software framework support is a must.
To build easy to use and maintain applications, software frameworks will have to support DIP in some form and two most common forms are Service Locator and Dependency Injection (DI).
Service Locator Pattern
The Service Locator pattern decouples service Consumers from their Providers by providing an intermediate locator, both Consumers and Providers are aware of Service Locator. The Consumer usually uses configuration file to specify what Provider to use so it can be changed by end users easily. The diagram below shows a typical Service Locator in an Application.
Intent of Pattern
- Allow a service consumer to consume different services without need for code change.
- Allow local and remote services to be accessed in a similar way.
- Allow caching of service providers reducing latency when service is accessed by another service consumer.
Pitfalls of Pattern
- Code can become hard to understand at times.
- Limited scope for use compared to DI.
Understanding the Example Code
I have taken a standard example used to explain Service Locator pattern for an application. All standard application will have to log errors, important events or debug messages, the logging code can be put inside application or some third party services can be used. If the application needs to switch logging service as per user needs or environmental constraints, then a Service Locator can be used to achieve this.
In example program, the application wants to switch between two logging service providers. The first provider uses tab spaces as separators for log file and second provides in CSV format.
To use Service Locator provided in the example program, follow the steps below.
Step 1: Create a configuration key to specify log service to be used and its values
In the program, we have specified LogService
as configuration key in application configuration file. The values to be assigned to this are TabLogger
and CSVLogger
to use respective log service. The configuration file is shown below with default value as TabLogger
.
="1.0"="utf-8"
<configuration>
<appSettings>
<add key="LogService" value="CSVLogger"/>
</appSettings>
</configuration>
Step 2: Register the service providers with Service Locator
To allow end user to switch between service providers, register them with Service Locator. In example program, it's done in Application.Startup event. My service providers are not heavy on system resources, so I have created the instances straight away, it's normally recommended to have lazy initialization, so you are not wasting system resources, even Service Locator can be modified to do so. The registration process is done as shown in below code:
private void Application_Startup(object sender, StartupEventArgs e)
{
ServiceLocator.ServiceLocator.AddService("TabLogger", new TabLoggingClass());
ServiceLocator.ServiceLocator.AddService("CSVLogger", new CSVLoggingClass());
}
Step 3: Use the Service Locator to locate service
In the program, MainWindow
class is using log service to log events so it can obtain instance of service provider using Service Locator as shown in code below. By using application configuration to specify which Service Locator to use, we are allowing user to change service providers dynamically.
private ILog log = ServiceLocator.ServiceLocator.GetService<ILog>
(ConfigurationManager.AppSettings["LogService"]);
Points of Interest
- The Service Locator given in my example is very simple, a real life application can some time have complex service locator logic and instance creation may occur via a Factory Pattern and service providers can exist in remote location as web service or WCF service.
- I found that classifying Service Locator pattern under IOC or DIP principle was the hardest thing many articles in web give different explanation for as to where it belongs and why. I have expressed my view here and I leave the readers to debate more about it.