BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 1.1+

Service Locator Design Pattern

The service locator pattern is a design pattern that is used to decouple a class from its dependencies. Rather than the dependant class instantiating its dependencies directly, they are requested from a centralised service locator object.

Example Service Locator

To demonstrate the use of the service locator pattern we will now create an example using sample classes that are similar to those in the Dependency Injection article. The client class will provide functionality that allows the monthly payments for a loan to be calculated based upon a price, deposit and duration. The actual calculation will be performed by a dependency that can be obtained from a service locator.

The code for the payment calculator and the standard interface that it implements is as follows:

public interface IPaymentCalculator
{
    decimal GetMonthlyPayment(decimal Price, decimal Deposit, int Years);
}


public class PaymentCalculator : IPaymentCalculator
{
    public decimal GetMonthlyPayment(decimal Price, decimal Deposit, int Years)
    {
        decimal total = Price * (1 + Years * 0.1M);
        decimal monthly = (total - Deposit) / (Years * 12);
        return Math.Round(monthly, 2, MidpointRounding.AwayFromZero);
    }
}

We can now create the service locator that will be responsible for providing the above dependency and the initialiser object. These are shown below.

NB: For brevity properties are defined using the .NET 3.0 automatically implemented property syntax. For earlier versions of the .NET framework, these should be expanded to include get and set accessors and backing store fields.

public class ServiceLocator
{
    private static ServiceLocator _serviceLocator;
    private static object _lockThis = new object();

    private IPaymentCalculator _paymentCalculator;

    private ServiceLocator() { }

    public static ServiceLocator GetServiceLocator()
    {
        lock (_lockThis)
        {
            if (_serviceLocator == null)
                _serviceLocator = new ServiceLocator();
        }
        return _serviceLocator;
    }

    public IPaymentCalculator GetPaymentCalculator()
    {
        return _paymentCalculator;
    }

    public void InitialiseService1(IPaymentCalculator calculator)
    {
        _paymentCalculator = calculator;
    }
}


public class Initialiser
{
    public void Initialise()
    {
        ServiceLocator locator = ServiceLocator.GetServiceLocator();
        locator.InitialiseService1(new PaymentCalculator());
    }
}

Lastly we need to create the PaymentTerms class. This is the class that depends upon an IPaymentCalculator instance to perform its calculations. Note that the GetMonthlyPayment method includes code that obtains the singleton service locator from which it requests an IPaymentCalculator.

public class PaymentTerms
{
    public decimal Price { get; set; }
    public decimal Deposit { get; set; }
    public int Years { get; set; }

    public decimal GetMonthlyPayment()
    {
        ServiceLocator locator = ServiceLocator.GetServiceLocator();
        IPaymentCalculator calculator = locator.GetPaymentCalculator();
        return calculator.GetMonthlyPayment(Price, Deposit, Years);
    }
}

Testing the Service Locator

We can now test the example service locator by generating a PaymentTerms object and requesting the monthly payment value. The code below demonstrates this. The first line creates a new Initialiser and uses it to configure the singleton service locator. The remainder of the code creates a PaymentTerms object, provides values for the properties and outputs the monthly payment amount.

new Initialiser().Initialise();

PaymentTerms pt = new PaymentTerms();
pt.Price = 10000;
pt.Years = 4;
pt.Deposit = 2500;
Console.WriteLine(pt.GetMonthlyPayment());  // Outputs "239.58"
18 October 2010