Service locator pattern is one of the most commonly used patterns. In general, this pattern is used along with other patterns like Adapter Pattern, Observer Pattern, Dependency Injection Principles and many more. In this post, however, we will be talking about its use with dependency injection, which is one its many uses.
Introduction
The service locator pattern works as a middleman between the application and the services used by it. The intent is to unbind the application from the services it uses. The application rather requests the locator to provide a service it requires at any point in time. However, an application may have a dedicated or a generic locator depending on the application requirements. A dedicated service locator serves the requests for a particular service, whereas a generic locator serves all the requests.
Scenario
In our previous post, we used Autofac in order to manage the dependencies of Commerce class. It's equally important to note, that our Commerce class may have some methods which use either of the dependencies or do not use any of them at all. And therefore, instantiating all the dependencies at once doesn't seem to be a good idea.
At this instant, a better approach to such a scenario would be, to instantiate a dependency "only" when it is required. Unlike instantiating all the dependencies at once, a service locator instantiates a dependency/service as and when required. Consequently, saving the runtime manager from the burden of managing in-memory dependency objects, which may never be used in the application again.
Implementing a Generic Service Locator
As can be seen in the code below, our Commerce class has multiple dependencies. The container instantiates all these dependencies for our first request of Commerce class object. And therefore, we use the service locator pattern to optimize our code for such scenarios.
- public class Commerce
- {
- private readonly PaymentProcessor _paymentProcessor;
- private readonly NotificationManager _notificationManager;
- private readonly Logger _logger;
- public Commerce(PaymentProcessor paymentProcessor, NotificationManager notificationManager, Logger logger)
- {
- _paymentProcessor = paymentProcessor;
- _notificationManager = notificationManager;
- _logger = logger;
- }
- public void ProcessOrder(Order order)
- {
- decimal paidAmount = order.UnitPrice * order.Quantity;
- bool paymentSuccessful = _paymentProcessor.ProcessPayment(paidAmount);
- if(paymentSuccessful)
- {
- _notificationManager.NotifyCustomer(notification: "payment successful");
- }
- else
- {
- _notificationManager.NotifyCustomer(notification: "payment failed");
- _logger.Log(errorMessage: "payment failed");
- }
- }
- }

Join the conversation! Your thoughts help the community grow.