Service Locator

The final anti-pattern that we will explore is the most dangerous one: the Service Locator.
It's funny because this is often considered a good pattern and is widely used, even in the famous Spring framework. Originally, the Service Locator pattern was defined in Microsoft patterns & practices' Enterprise Library, as Mark Seeman writes in his book "Dependency Injection in NET", Chapter 5.4 - Service Locator, but now he is advocating strongly against it. Service Locator is a common name for a service that we can query for different objects that were previously registered in it. As mentioned, it is a tricky one because it makes everything seem OK, but in fact, it nullifies all the advantage of the Dependency Injection:

let locator = ServiceLocator.instance
locator.register( SqlLiteTodosRepository(),
forType: TodosRepository.self)

class TodosService {
private let repository: TodosRepository

init() {
let locator = ServiceLocator.instance
self.repository = locator.resolve(TodosRepository.self)
}
}

Here we have a service locator as a singleton, to whom we register the classes we want to resolve. Instead of injecting the class into the constructor, we just query from the service. It looks like the Service Locator has all the advantages of Dependency Injection, it provides testability and extensibility since we can use different implementations without changing the client. It also enables parallel development and separated configuration from the usage.

But it has some major disadvantages. With DI, the dependencies are explicit; it's enough to look at the signature of the constructor or the exposed properties to understand what the dependencies for a class are. With a Service Locator, these dependencies are implicit, and the only way to find them is to inspect the implementation, which breaks the encapsulation.
Also, all the classes are depending on the Service Locator and this makes the code tightly coupled with it. If we want to reuse a class, other then that class, we also need to add the Service Locator in our project, which could be in a different module and then adding the whole module as dependency where we wanted just to use one class. Service Locator could also give us the impression that we are not using DI at all because all the dependencies are hidden inside the classes.

To sum up, pay attention to these anti-patterns and if you have any of those, you must refactor them using the Constructor Injection and the Composition Root.