Есть ли опыт работы с внедрением зависимостей (DI)?

«Есть ли опыт работы с внедрением зависимостей (DI)?» — вопрос из категории DI, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, я использовал различные подходы к внедрению зависимостей во Flutter для создания тестируемого и слабосвязанного кода.

1. Использование пакета get_it (Service Locator): Применял в проектах, где нужен был простой и глобальный доступ к сервисам.

// Настройка локатора (обычно в main.dart или отдельном файле)
final getIt = GetIt.instance;

void setupDependencies() {
  // Регистрируем синглтон (один экземпляр на всё приложение)
  getIt.registerSingleton<ApiService>(ApiService());
  // Регистрируем фабрику (новый экземпляр при каждом запросе)
  getIt.registerFactory<LoginBloc>(() => LoginBloc(getIt<ApiService>()));
  // Регистрируем ленивый синглтон (создается при первом запросе)
  getIt.registerLazySingleton<SharedPreferencesService>(
    () => SharedPreferencesService(),
  );
}

// Использование в коде
class MyRepository {
  final ApiService _api = getIt<ApiService>(); // Внедрение через локатор
  Future<Data> fetchData() => _api.getData();
}

2. Использование provider/riverpod (управление состоянием с DI): Эти пакеты не только управляют состоянием, но и естественным образом решают задачу DI через контекст.

// Настройка провайдеров с Riverpod
final apiServiceProvider = Provider<ApiService>((ref) => ApiService());
final repositoryProvider = Provider<MyRepository>(
  (ref) => MyRepository(ref.watch(apiServiceProvider)),
);

// Использование в виджете
class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final repository = ref.watch(repositoryProvider); // Зависимость получена
    // ...
  }
}

Почему это важно:

  • Тестируемость: Легко подменить реальный ApiService на мок в тестах.
  • Слабая связность: Классы не создают свои зависимости жестко, а получают их извне.
  • Управление жизненным циклом: DI-контейнер (get_it или riverpod) контролирует, когда создавать и пересоздавать экземпляры (синглтон, фабрика).

В сложных проектах также рассматривал решения вроде injectable для кодогенерации на основе аннотаций.