The ServiceLocator design pattern builds loosely coupled modules that can be independently developed, tested, and deployed seamlessly Design patterns are solutions to recurring problems and complexities in software design. The ServiceLocator design pattern promotes loose coupling but sans the need of injecting dependencies through constructors, properties or interfaces. This is a popular design pattern that can be used to decouple the service consumers from the concrete classes implementing such services. The ServiceLocator is responsible for returning instances of services when they are requested for by the service consumers or the service clients. In essence, the service consumers or the service clients are not aware of the types that have the service actually implemented in them, rather, the service clients need to take advantage of the service locator to retrieve a reference object to the actual service implementation class. The components participating in the ServiceLocator design pattern include the following: ServiceLocator — The ServiceLocator abstracts the creation of the dependencies and if might also act as a repository of service objects that have already been created and initialized. Initializer — This is responsible for initializing the service instances at runtime. Once these objects have been initialized, they are stored in the ServiceLocator. Client — This represents the service consumer or the service client. Service(s) — This represents the actual service contracts and their implementations. Implementing the ServiceLocator pattern In this section we will explore how we can implement the ServiceLocator design pattern in C#. Let’s now dig into a bit of code. To get started, create a WCF Application Project in Visual Studio IDE. Next, create two services named, CustomerService and ProductService. Here’s how the service contracts look like — I’ve incorporated a simple OperationContract (service operation) in each of these services. [ServiceContract] public interface ICustomerService { [OperationContract] string GetText(); } [ServiceContract] public interface IProductService { [OperationContract] string GetText(); } The implementation of the ProductService and CustomerService classes is given below. Note that these service implementation classes implement the IProductService and ICustomerService interfaces (service contracts) respectively. public class ProductService : IProductService { public string GetText() { return "This is the Product Service..."; } } public class CustomerService : ICustomerService { public string GetText() { return "This is the Customer Service..."; } } And, now, we would create the ServiceLocator class. This class would be static in nature and would contain a Dictionary to store the service instances. Besides, the ServiceLocator class would also contain the GetService and RegisterService methods. While the former will be used to retrieve a particular service instance, the latter would be used to store services instances inside the ServiceLocator’s Dictionary instance named “registeredServices”. Here’s the complete source code of the ServiceLocator class. public static class ServiceLocator { private static readonly Dictionary<Type, object> registeredServices = new Dictionary<Type, object>(); public static T GetService<T>() { return (T)registeredServices[typeof(T)]; } public static void RegisterService<T>(T service) { registeredServices[typeof(T)] = service; } public static Int32 Count { get { return registeredServices.Count; } } } Now that we have created a simple ServiceLocator class, let’s explore how we can take advantage of it to locate and use services. Here’s how you can use the ServiceLocator class we just created — I’ve used a console application here to demonstrate how the services can be located with simplicity. You can feel free to use the same code anywhere in your application where you would need to register and then locate services. static void Main(string[] args) { ICustomerService customerService = new CustomerService(); IProductService productService = new ProductService(); ServiceLocator.RegisterService(customerService); ServiceLocator.RegisterService(productService); ICustomerService testService = ServiceLocator.GetService<ICustomerService>(); string msg = testService.GetText(); Console.WriteLine(msg); Console.Read(); } Note that in this example I’ve not used a separate class to represent the Initializer component we discussed earlier since the initialization code has been embedded inside the ServiceLocator class. The ServiceLocator design pattern is a good choice when you would want to decouple your classes from their dependencies but with minimal change in your application’s source code. Another good candidate for implementing this design pattern is when you would want to isolate the dependencies and especially when these dependencies are not known at the compile time. In other words, you can leverage the ServiceLocator design pattern when you need to design classes that in turn depend on classes whose concrete implementations aren’t known at compile time. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos