Sobes.tech
Назад к вопросам
Junior — Middle
121

Могли бы вы объяснить отличие между Dependency Injection и паттерном локатора сервисов?

Компании, где спрашивали
HamkorBank

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Dependency Injection и Service Locator решают одну проблему — как получить зависимости, — но делают это по-разному. При Dependency Injection зависимость передаётся извне, а при Service Locator объект сам запрашивает нужный сервис из общего реестра. Обычно DI считают более предпочтительным, потому что он делает зависимости явными и упрощает тестирование. Service Locator чаще критикуют за скрытые зависимости и сильную связанность с глобальным контейнером.

Определение:

Dependency Injection (DI) — это способ организации кода, при котором объект не создаёт свои зависимости сам и не ищет их, а получает их снаружи: через конструктор, параметры метода или поля.

Service Locator — это паттерн, где есть общий объект-реестр, у которого можно запросить нужный сервис по имени или типу. Объект сам вызывает локатор и получает зависимость внутри своей логики.

Ключевая разница: при DI зависимости видны снаружи, а при Service Locator они скрыты внутри объекта.

Пример использования:

Допустим, есть экран, которому нужен репозиторий данных.

class UserRepository {
  String loadUserName() => 'Alice';
}

// Dependency Injection
class UserScreenDI {
  final UserRepository repository;

  UserScreenDI(this.repository);

  void showUser() {
    print(repository.loadUserName());
  }
}

// Service Locator
class ServiceLocator {
  static final _services = <Type, Object>{};

  static void register<T>(T service) {
    _services[T] = service as Object;
  }

  static T get<T>() {
    return _services[T] as T;
  }
}

class UserScreenSL {
  void showUser() {
    final repository = ServiceLocator.get<UserRepository>();
    print(repository.loadUserName());
  }
}

Пояснение кода:

В варианте с DI UserScreenDI получает UserRepository через конструктор. Это значит, что при создании экрана сразу видно, какая зависимость ему нужна. Такой класс проще тестировать: можно передать mock или fake-реализацию.

В варианте с Service Locator UserScreenSL сам обращается к ServiceLocator.get<UserRepository>(). Снаружи кажется, что класс не зависит ни от чего, но на самом деле зависимость спрятана внутри метода. Чтобы код работал, сервис должен быть заранее зарегистрирован через register().

По шагам:

  1. Создаётся реализация UserRepository.
  2. В DI она передаётся в UserScreenDI извне.
  3. В Service Locator она сначала регистрируется в общем хранилище.
  4. UserScreenSL сам запрашивает её через локатор в момент использования.

Ключевые моменты:

  • DI делает зависимости явными, Service Locator — скрытыми.
  • DI обычно лучше для тестирования и сопровождения кода.
  • Service Locator может быть удобен, но повышает связанность с глобальным контейнером.
  • При DI объект меньше знает о том, откуда берутся его зависимости.
  • При Service Locator сложнее понять, что нужно классу, просто посмотрев на его интерфейс.
  • В Flutter часто используют DI-подход через конструкторы, провайдеры или контейнеры внедрения зависимостей.