Является ли ServiceLocator антишаблоном?
Недавно я прочиталСтатья Марка Симанна о сервисном локаторе анти-паттерна.
Автор указывает на две основные причины, по которым ServiceLocator является антишаблоном:
Проблема использования API (с которым я в порядке)
Когда в классе используется локатор Service, очень трудно увидеть его зависимости, так как в большинстве случаев у класса есть только один конструктор PARAMETERLESS. В отличие от ServiceLocator, подход DI явно предоставляет зависимости через параметры конструктора, поэтому зависимости легко увидеть в IntelliSense.
Вопрос обслуживания (что озадачивает меня)
Рассмотрим следующий пример
У нас есть класс'Мой тип' который использует подход локатора службы:
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();
}
}
И здесь начинается мое недоразумение. Автор говорит:
Становится намного сложнее сказать, вводите ли вы критические изменения или нет. Вы должны понимать все приложение, в котором используется локатор служб, и компилятор вам не поможет.
Но подождите секунду, если бы мы использовали подход DI, мы бы ввели зависимость с другим параметром в конструктор (в случае внедрения конструктора). И проблема все еще будет там. Если мы можем забыть настроить ServiceLocator, тогда мы можем забыть добавить новое отображение в наш контейнер IoC, и подход DI будет иметь ту же проблему во время выполнения.
Также автор упомянул о сложностях модульного тестирования. Но разве у нас не будет проблем с подходом DI? Не нужно ли нам обновить все тесты, которые создавали этот класс? Мы обновим их, чтобы они передавали новую ложную зависимость, чтобы сделать наш тест компилируемым. И я не вижу никакой пользы от этого обновления и затрат времени.
Я не пытаюсь защищать подход Service Locator. Но это недоразумение заставляет меня думать, что я теряю что-то очень важное. Может ли кто-нибудь развеять мои сомнения?
ОБНОВЛЕНИЕ (РЕЗЮМЕ):
Ответ на мой вопрос «Является ли Service Locator антишаблоном» действительно зависит от обстоятельств. И я бы точно не советовал вычеркивать это из вашего списка инструментов. Это может стать очень удобным, когда вы начнете работать с устаревшим кодом. Если вам повезло оказаться в самом начале вашего проекта, тогда подход DI может быть лучшим выбором, поскольку он имеет некоторые преимущества по сравнению с Service Locator.
И вот основные отличия, которые убедили меня не использовать Service Locator для моих новых проектов:
Самое очевидное и важное: Service Locator скрывает зависимости классовЕсли вы используете какой-либо контейнер IoC, он, вероятно, будет сканировать весь конструктор при запуске, чтобы проверить все зависимости и немедленно дать вам отзыв о пропущенных сопоставлениях (или неправильной конфигурации); это невозможно, если вы используете свой контейнер IoC в качестве локатора службыДля подробностей читайте отличные ответы, которые приведены ниже.