Внедрение зависимости Что является большим улучшением? - PullRequest
10 голосов
/ 09 октября 2011

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

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

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 и модульное тестирование моего контроллера.

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

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

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

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

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

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

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

Ответы [ 3 ]

10 голосов
/ 09 октября 2011

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

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

5 голосов
/ 09 октября 2011

Внедрение зависимостей полезно по 3 основным причинам:

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

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

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

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

0 голосов
/ 09 октября 2011

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

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

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

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

...