В чем разница между шаблонами Dependency Injection и Service Locator? - PullRequest
260 голосов
/ 13 октября 2009

Обе модели кажутся реализацией принципа инверсии управления. То есть объект не должен знать, как построить свои зависимости.

Внедрение зависимостей (DI), похоже, использует конструктор или установщик для "внедрения" своих зависимостей.

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

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Сервисный локатор, похоже, использует «контейнер», который связывает его зависимости и выдает его в виде бара.

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

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}

Поскольку наши зависимости - это просто сами объекты, эти зависимости имеют зависимости, которые имеют еще больше зависимостей, и так далее, и тому подобное. Таким образом, Инверсия Контейнера Контроля (или Контейнера DI) родилась. Примеры: Замок Виндзор, Нинъект, Карта структуры, Весна и т. Д.)

Но Контейнер IOC / DI выглядит точно как Локатор Сервиса. Называет ли это контейнер DI плохим именем? Является ли контейнер IOC / DI просто еще одним типом сервисного локатора? Есть ли нюанс в том, что мы используем DI-контейнеры в основном, когда у нас много зависимостей?

Ответы [ 13 ]

3 голосов
/ 10 января 2012

Примечание: я не совсем отвечаю на вопрос. Но я чувствую, что это может быть полезно для новых изучающих шаблон «Внедрение зависимостей», которые путаются с ним с шаблоном Service Locator (anti-) , которые случайно наткнулись на эту страницу.

Мне известна разница между локатором службы (теперь он рассматривается как анти-шаблон) и шаблонами внедрения зависимостей, и я могу понять конкретные примеры каждого шаблона, но меня смутили примеры, показывающие локатор службы внутри конструктора ( предположим, что мы делаем инъекцию в конструктор).

«Сервисный локатор» часто используется как в качестве имени шаблона, так и в качестве имени для ссылки на объект (предположим, тоже), который используется в этом шаблоне для получения объектов без использования оператора new. Теперь этот же тип объекта можно также использовать в корне композиции для выполнения внедрения зависимостей, и здесь возникает путаница.

Следует отметить, что вы можете использовать объект локатора службы внутри конструктора DI, но вы не используете «шаблон локатора службы». Это менее запутанно, если вместо этого кто-то называет его контейнерным объектом IoC, поскольку вы, возможно, догадались, что они, по сути, делают то же самое (исправьте меня, если я ошибаюсь).

Независимо от того, называется ли он локатором службы (или просто локатором), или контейнером IoC (или просто контейнером), не имеет значения, как вы уже догадались, поскольку они, вероятно, ссылаются на одну и ту же абстракцию (исправьте меня, если я я не прав) Просто называя его локатором сервисов, можно предположить, что каждый использует анти-паттерн сервисного локатора вместе с паттерном внедрения зависимостей.

ИМХО, называя его «локатором» вместо «местоположения» или «определения местоположения», иногда можно подумать, что локатор службы в статье ссылается на контейнер локатора службы, а не на локатор службы (анти-локатор службы). -) шаблон, особенно когда есть связанный шаблон, называемый Dependency Injection, а не Dependency Injector.

1 голос
/ 23 января 2017

В чем разница (если есть) между внедрением зависимости и сервисным локатором? Оба шаблона хороши в реализации принципа инверсии зависимости. Шаблон Service Locator легче использовать в существующей кодовой базе, поскольку он делает общий дизайн более свободным, не вызывая изменений в общедоступном интерфейсе. По этой же причине код, основанный на шаблоне локатора службы, менее читаем, чем эквивалентный код, основанный на внедрении зависимостей.

Шаблон внедрения зависимостей проясняет, так как сигнатура зависит от класса (или метода). По этой причине полученный код становится чище и более читабельным.

0 голосов
/ 30 сентября 2018

Для записи

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Если вам действительно не нужен интерфейс (интерфейс используется более чем одним классом), вы НЕ ДОЛЖНЫ ИСПОЛЬЗОВАТЬ ЕГО . В этом случае IBar позволяет использовать любой класс обслуживания, который его реализует. Однако, как правило, этот интерфейс будет использоваться одним классом.

Почему плохая идея использовать интерфейс? Потому что это действительно сложно отладить.

Например, допустим, что экземпляр "bar" не выполнен, вопрос: , какой класс вышел из строя? и именно здесь заканчивается моя дорога.

Вместо этого, если код использует жесткую зависимость, легко отладить ошибку.

//Foo Needs an IBar
public class Foo
{
  private BarService bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Если "bar" не работает, я должен проверить и запустить класс BarService.

...