Ответ
Service Locator (Локатор служб) — это паттерн, предоставляющий глобальный реестр для доступа к сервисам (зависимостям) приложения, таким как API-клиенты, репозитории, настройки. Вместо того чтобы передавать зависимости через конструкторы по всему дереву виджетов (как при Dependency Injection), мы "локализуем" их в одном месте.
Популярная реализация во Flutter — пакет get_it:
-
Настройка (регистрация зависимостей):
// service_locator.dart import 'package:get_it/get_it.dart'; final getIt = GetIt.instance; void setupLocator() { // Регистрируем синглтон (один экземпляр на все приложение) getIt.registerSingleton<ApiClient>(ApiClient()); // Регистрируем фабрику (новый экземпляр при каждом запросе) getIt.registerFactory<LoginBloc>(() => LoginBloc()); // Регистрируем ленивый синглтон (создается при первом запросе) getIt.registerLazySingleton<AuthRepository>(() => AuthRepositoryImpl()); // Регистрация с зависимостью getIt.registerSingleton<UserService>(UserService(getIt<ApiClient>())); } -
Использование в коде:
// В бизнес-логике (Cubit/BLoC) class UserCubit extends Cubit<UserState> { final UserService _userService = getIt<UserService>(); // Получаем сервис UserCubit() : super(UserInitial()); void loadUser() async { final user = await _userService.getCurrentUser(); emit(UserLoaded(user)); } } // В UI (если нужно, но лучше избегать) Widget build(BuildContext context) { final authService = getIt<AuthRepository>(); return Text('User: ${authService.currentUser?.name}'); }
Плюсы:
- Простота: Легко начать использовать, не требуется оборачивать все приложение в провайдеры.
- Глобальный доступ: Удобен для сервисов, которые нужны "везде" (навигация, аналитика).
- Упрощает навигацию: Легко получить доступ к BloC из другого экрана.
Минусы и предостережения:
- Скрытые зависимости: Код становится менее явным, сложнее отследить, от чего зависит класс.
- Усложнение тестирования: Требуется сбрасывать или переопределять зависимости в локаторе перед каждым тестом.
- Нарушение инверсии зависимостей: Классы зависят от конкретной реализации локатора, а не от абстракций.
Когда использовать? Для небольших проектов, прототипов или для истинно глобальных сервисов (например, FirebaseAnalytics). Для больших, тестируемых приложений предпочтительнее использовать внедрение зависимостей через конструктор в сочетании с пакетами типа provider или riverpod, которые обеспечивают лучшую управляемость и тестируемость.