Какие проблемы есть у Service Locator паттерна
Что проверяют
Понимаете ли вы разницу между «объект сам достаёт зависимости» и «зависимости ему передают». Интервьюеру важны практические последствия для тестов и модульности, а не только слово «антипаттерн». Следом часто спрашивают, чем здесь отличается DI-контейнер вроде Swinject и бывает ли локатор оправдан.
Как отвечать
Service Locator это общий реестр, у которого класс сам запрашивает сервис: ServiceLocator.shared.resolve(APIClient.self). Проблемы вытекают из этой схемы:
- скрытые зависимости: по инициализатору не видно, что нужно классу. Их находят только поиском вызовов
resolveпо коду; - ошибки в рантайме вместо компиляции: забыли зарегистрировать сервис, и приложение падает на force unwrap или
fatalErrorпри открытии экрана, а компилятор молчит. При внедрении черезinitтакой код просто не соберётся; - тесты: чтобы подменить зависимость, приходится менять глобальное состояние. Тесты начинают влиять друг на друга;
- связанность с локатором: каждый класс зависит от глобального синглтона, и вынести его в отдельный Swift Package без этого реестра сложно;
- потокобезопасность: регистрация и чтение из разных потоков требуют синхронизации, а в режиме Swift 6 глобальное изменяемое состояние компилятор помечает как небезопасное.
Альтернатива: внедрение через инициализатор и сборка графа в одном месте (composition root, координатор, фабрика модуля). Swinject остаётся удобным, если обращаться к контейнеру только в точке сборки, а не из каждого класса. Честно назовите и плюсы локатора: мало кода, легко внедрить в легаси. В SwiftUI @Environment похож на локатор по форме, но значения передаются по иерархии вью и легко подменяются в превью.
Где спотыкаются
Называют главным минусом производительность. Поиск по словарю типов быстрый, реальные проблемы в неявности и тестах.
Говорят, что Swinject это DI, поэтому проблем нет. Если container.resolve вызывается внутри вью-моделей, это тот же Service Locator под другим названием.
Отвечают «это антипаттерн» и не могут показать, как переделать. Покажите переход: зависимость в init, протокол вместо конкретного типа, сборка в фабрике экрана.