Зависимость Инъекция, что является большим улучшением?

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

Хорошо, я начну с примерного контроллера (примера приложения MVC приложения asp.net для диспетчера контактов)

public class ContactsController{

  ContactsManagerDb _db;

  public ContactsController(){

    _db = ContactsManagerDb();

  } 

  //...Actions here
}

Хорошо, здорово, что работает. Мои действия могут использовать базу данных для действий CRUD. Теперь я решил, что хочу добавить модульное тестирование, и я добавил еще один конструктор, чтобы издеваться над базой данных

public class ContactsController{

  IContactsManagerDb _db;

  public ContactsController(){

    _db = ContactsManagerDb();

  }

  public ContactsController(IContactsManagerDb db){
    _db = db;
  }

  //...Actions here
}

Удивительно, что в моих модульных тестах я могу создать свою собственную реализацию контроллера IContactsManagerDb и unit test.

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

Итак, используя StructureMap, я добавил следующее правило инъекции:

x.For<IContactsManagerDb>().Use<ContactsManagerDb>();

И, конечно же, в моем тестовом проекте я использую другую реализацию IContactsManagerDb.

x.For<IContactsManagerDb>().Use<MyTestingContactsManagerDb>();

Но мой вопрос: ** Какую проблему я решил или что упростил, используя инъекцию зависимостей в этом конкретном случае?

Я не вижу никакого практического использования этого сейчас, я понимаю, КАК, но НЕ ПОЧЕМУ? Какая польза от этого? Может ли кто-нибудь добавить к этому проекту, возможно, привести пример, как это более практично и полезно?

Ответ 1

Первый пример не является проверяемым модулем, поэтому он не очень хорош, так как он создает сильную связь между различными слоями приложения и делает их менее многоразовыми. Второй пример называется инъекция зависимых людей. Он также обсудил here.

Что не так с инъекцией зависимостей бедных людей, так это то, что код не является автодокументацией. Он не заявляет о своем намерении потребителю. Потребитель видит этот код, и он может легко вызвать конструктор по умолчанию, не передавая никакого аргумента, тогда как если бы не было конструктора по умолчанию, было бы сразу ясно, что этот класс абсолютно требует, чтобы какой-то контракт передавался его конструктору для нормальной работы. И на самом деле это не класс, чтобы решить, какую конкретную реализацию выбрать. Это зависит от потребителя этого класса.

Ответ 2

Включение зависимости полезно по трем основным причинам:

  • Это метод развязки интерфейсов и реализаций.
  • Это полезно для уменьшения количества методов плиты котла / factory в приложении.
  • Это увеличивает модульность пакетов.

В качестве примера рассмотрим Unit test, который требует доступа к классу, определенному как интерфейс. Во многих случаях Unit test для интерфейса должен был бы ссылаться на реализации этого интерфейса - таким образом, если бы реализация изменилась, то и unit test. Однако с помощью DI вы можете "внедрить" реализацию интерфейса во время выполнения в Unit test с помощью API инъекций, так что изменения в реализациях должны обрабатываться только инфраструктурой инъекции, а не отдельными классами, использующими эти реализации.

Еще один пример в веб-мире: рассмотрите связь между поставщиками услуг и определениями служб. Если какой-либо конкретный компонент нуждается в доступе к сервису, лучше сконструировать его для интерфейса, чем для конкретной реализации этой службы. Injection позволяет такой дизайн, опять же, позволяя динамически добавлять зависимости, ссылаясь на вашу инфраструктуру инъекций.

Таким образом, различные сочетания классов друг с другом переносятся из заводов и отдельных классов и рассматриваются единообразным, абстрактным, многоразовым и легко поддерживаемым образом, когда у них есть хорошая основа DI. Лучшие учебники по DI, которые я видел, находятся в учебниках по Google Guice, доступных на YouTube. Хотя они не совпадают с вашей конкретной технологией, принципы идентичны.

Ответ 3

Во-первых, ваш пример не будет компилироваться. var _db; не является допустимым, потому что тип переменной должен быть выведен при объявлении.

Вы можете сделать var _db = new ContactsManagerDb();, но тогда ваш второй конструктор не будет компилироваться, потому что вы пытаетесь назначить IContactsManagerDb экземпляру ContactsManagerDb.

Вы можете изменить его на IContactsManagerDb _db;, а затем убедитесь, что ContactsManagerDb происходит от IContactsManagerDb, но затем это делает ваш первый конструктор нерелевантным. У вас должен быть конструктор, который всегда принимает аргумент интерфейса, поэтому почему бы просто не использовать его все время?

Инъекция зависимостей - это все об удалении зависимостей от самих классов. ContactsController не нужно знать о ContactsManagerDb, чтобы использовать IContactsManagerDb для доступа к диспетчеру контактов.