Service locator pattern
The service locator pattern is a design pattern used to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the “service locator”, which on request returns the information necessary to perform a certain task. Proponents of the pattern say the approach simplifies component-based applications where all dependencies are cleanly listed at the beginning of the whole application design, consequently making traditional dependency injection a more complex way of connecting objects.
Example
First of all let’s create two services which will perform some operations:
class Service1 {
fun action() {
println("Action from Service 1")
}
}
class Service2 {
fun action() {
println("Action from Service 2")
}
}
After that we will create ServiceLocator
interface and it’s implementation:
interface ServiceLocator {
val service1: Service1
val service2: Service2
}
class ServiceLocatorImpl: ServiceLocator {
override val service1: Service1 by lazy { Service1() }
override val service2: Service2 by lazy { Service2() }
}
Then, I assumed that we have a class that needs two services to perform some operation. It will receive these two services with the help of a Patter - Service Locator:
class ServiceComposition(serviceLocator: ServiceLocator) {
private val service1 = serviceLocator.service1
private val service2 = serviceLocator.service2
fun serviceInteraction() {
service1.action()
service2.action()
}
}
and finally, example of usage:
class ServiceLocatorExample() {
fun example() {
val serviceLocator: ServiceLocator = ServiceLocatorImpl()
val serviceComposition = ServiceComposition(serviceLocator)
serviceComposition.serviceInteraction()
}
}
Output:
Action from Service 1
Action from Service 2
Conclusion
Advantages:
- The “service locator” can act as a simple run-time linker. This allows code to be added at run-time without re-compiling the application, and in some cases without having to even restart it;
- Applications can optimize themselves at run-time by selectively adding and removing items from the service locator;
- Large sections of a library or application can be completely separated. The only link between them becomes the registry;
- An application may use multiple structured service locators purposed for particular functionality/testing. Service locator does not mandate one single static class per process;
- The solution may be simpler with service locator (vs. dependency injection) in applications with well-structured component/service design.
Disadvantages
- The registry hides the class’ dependencies, causing run-time errors instead of compile-time errors when dependencies are missing (similar to using dependency injection);
- The registry makes code harder to test, since all tests need to interact with the same global service locator class to set the fake dependencies of a class under test.
Links
Further reading
Service Locator pattern in Android
Inversion of Control Containers and the Dependency Injection pattern
Why service locator is so unpopular