Что такое паттерн Service Locator?

«Что такое паттерн Service Locator?» — вопрос из категории Паттерны, который задают на 23% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Service Locator (Локатор служб) — это паттерн проектирования, который предоставляет глобальный реестр для поиска и получения зависимостей (сервисов), скрывая детали их создания. Это альтернатива Dependency Injection (DI), где зависимости не "внедряются", а "запрашиваются" клиентом.

Базовая реализация на Swift:

class ServiceLocator {
    static let shared = ServiceLocator()
    private var services: [String: Any] = [:]

    // Регистрация сервиса по его типу
    func register<T>(_ service: T) {
        let key = String(describing: T.self)
        services[key] = service
    }

    // Разрешение (получение) сервиса по типу
    func resolve<T>() -> T? {
        let key = String(describing: T.self)
        return services[key] as? T
    }
}

// 1. Регистрация сервисов (обычно при запуске приложения)
ServiceLocator.shared.register(NetworkService())
ServiceLocator.shared.register(DatabaseService())

// 2. Использование в коде
class ViewModel {
    // Зависимость неявно получена через локатор
    private let networkService: NetworkService? = ServiceLocator.shared.resolve()
}
Сравнение с Dependency Injection (DI): Аспект Service Locator Dependency Injection (через конструктор)
Видимость зависимостей Скрыты (класс сам их ищет) Явные (передаются как параметры)
Тестируемость Сложнее, требует настройки локатора в тестах Легче, зависимости можно передать как mock/stub
Связность кода Выше (класс знает о локаторе) Ниже (класс знает только о своих интерфейсах)

Недостатки (почему часто считается антипаттерном):

  • Скрытые зависимости: Усложняет понимание того, от чего зависит класс.
  • Усложняет тестирование: Требует конфигурации глобального состояния (shared) для каждого теста.
  • Зависимость от глобального состояния: Противоречит принципам модульности и может привести к непредсказуемому поведению.