Недавно я прочитал статью Mark Seemann об анти-шаблоне Locator Service Locator.
Автор указывает две основные причины, по которым ServiceLocator является анти-шаблоном:
-
Проблема с API-интерфейсом (с которой я отлично справляюсь)
Когда класс использует локатор службы, очень сложно увидеть его зависимости, так как в большинстве случаев класс имеет только один конструктор PARAMETERLESS. В отличие от ServiceLocator, подход DI явно раскрывает зависимости через параметры конструктора, поэтому зависимости легко видны в IntelliSense. -
Проблема с обслуживанием (что меня озадачивает)
Рассмотрим следующий пример
У нас есть класс "MyType", который использует подход локатора сервисов:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Теперь мы хотим добавить другую зависимость в класс 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
И вот здесь начинается мое недоразумение. Автор говорит:
Становится намного сложнее сказать, вводите ли вы нарушение или нет. Вам нужно понять все приложение, в котором используется Locator службы, и компилятор не поможет вам.
Но подождите секунду, если мы будем использовать подход DI, мы представим зависимость с другим параметром в конструкторе (в случае инъекции конструктора). И проблема все равно будет. Если мы можем забыть установить ServiceLocator, то мы можем забыть добавить новое сопоставление в наш контейнер IoC, а подход DI будет иметь одинаковую проблему во время выполнения.
Кроме того, автор упомянул о трудностях unit test. Но разве у нас не будет проблем с подходом DI? Не нужно ли нам обновлять все тесты, которые создавали этот класс? Мы обновим их, чтобы передать новую издеваемую зависимость, чтобы сделать наш тестовый компилятор. И я не вижу никаких преимуществ от этого обновления и времени.
Я не пытаюсь защитить подход Service Locator. Но это недоразумение заставляет меня думать, что я теряю что-то очень важное. Может ли кто-нибудь развеять мои сомнения?
ОБНОВЛЕНИЕ (РЕЗЮМЕ):
Ответ на мой вопрос "Является ли Service Locator анти-шаблоном" действительно зависит от обстоятельств. И я определенно не предлагаю перечеркнуть его из списка инструментов. Это может стать очень удобным, когда вы начнете работать с устаревшим кодом. Если вам посчастливилось быть в самом начале вашего проекта, подход DI может быть лучшим выбором, поскольку он имеет некоторые преимущества перед Service Locator.
И вот основные отличия, которые убедили меня не использовать Service Locator для моих новых проектов:
- Наиболее очевидный и важный: Service Locator скрывает зависимости класса
- Если вы используете какой-либо контейнер IoC, он, скорее всего, сканирует весь конструктор при запуске, чтобы проверить все зависимости и дать вам немедленную обратную связь по отсутствующим сопоставлениям (или неправильной конфигурации); это невозможно, если вы используете свой контейнер IoC в качестве Locator
Подробнее читайте превосходные ответы, которые приводятся ниже.