Зачем вам нужен Dependency Injection без настройки? - PullRequest
5 голосов
/ 03 февраля 2009

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

Теперь у меня возникает вопрос: зачем вам использовать DI-фреймворк, который не использует файлы конфигурации? Не в этом ли смысл использования инфраструктуры DI, чтобы вы могли изменить поведение (так сказать, «стратегию») после сборки / выпуска / любого кода?

Может кто-нибудь дать мне хороший пример использования, который проверяет использование ненастроенного DI, такого как Ninject?

Ответы [ 9 ]

10 голосов
/ 03 февраля 2009

Не думаю, что вам нужна DI-инфраструктура без конфигурации. Я думаю, вам нужен DI-фреймворк с конфигурацией , вам нужно .

Я возьму весну в качестве примера. В прежние времена мы обычно помещали все в файлы XML, чтобы все можно было настраивать.

При переключении в полностью аннотированный режим вы в основном определяете, какой компонент ролей содержит ваше приложение. Итак, данный сервис может, например, иметь одну реализацию, которая предназначена для «обычного времени выполнения», где есть другая реализация, которая принадлежит в «заглушенной» версии приложения. Кроме того, при подключении для интеграционных тестов вы можете использовать третью реализацию.

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

Таким образом, если вы позволите «конфигурации» просто указать, какие роли компонентов вам нужны, вы можете уйти без всякой дополнительной настройки. Конечно, всегда будут исключения, но тогда вы просто обрабатываете исключения.

5 голосов
/ 03 февраля 2009

Я нахожусь на пути к krosenvold, здесь, только с меньшим количеством текста: в большинстве приложений у вас есть ровно одна реализация на требуемую «услугу». Мы просто не пишем приложения, где каждому объекту нужно 10 или более реализаций каждого сервиса. Поэтому было бы разумно иметь простой способ сказать: «Это реализация по умолчанию, 99% всех объектов, использующих этот сервис, будут довольны».

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

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

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

3 голосов
/ 04 февраля 2009

Я получил этот комментарий в своем блоге от Нейт Кохари :

Рад, что вы рассматриваете возможность использования Ninject! Ninject считает, что Конфигурация вашей DI Framework является на самом деле часть вашего приложения, и не должен быть публично настраиваемым. Если Вы хотите, чтобы определенные привязки были настраивается, вы можете легко сделать Ninject модули читают ваш app.config. Наличие ваших привязок в коде спасает вас от многословия XML, и дает вы вводите безопасность, рефакторируемость и IntelliSense.

3 голосов
/ 03 февраля 2009

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

1 голос
/ 03 февраля 2009

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

DI приводит к более чистому, более отделенному дизайну - и это дает преимущества во всем.

1 голос
/ 03 февраля 2009

вам даже не нужно использовать инфраструктуру DI для применения шаблона внедрения зависимостей. вы можете просто использовать статические фабричные методы для создания ваших объектов, если вам не нужна конфигурируемость, кроме перекомпиляции кода.

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

0 голосов
/ 03 февраля 2009

Когда вы используете инверсию контроля, вы помогаете вашему классу делать как можно меньше. Допустим, у вас есть служба Windows, которая ожидает файлы, а затем выполняет серию процессов над файлом. Один из процессов - преобразовать его в ZIP, а затем отправить по электронной почте.

public class ZipProcessor : IFileProcessor
{
  IZipService ZipService;
  IEmailService EmailService;

  public void Process(string fileName)
  {
    ZipService.Zip(fileName, Path.ChangeFileExtension(fileName, ".zip"));
    EmailService.SendEmailTo(................);
  }
}

Зачем этому классу на самом деле делать архивирование и отправку по электронной почте, когда у вас могут быть специальные классы, чтобы сделать это для вас? Очевидно, что вы этого не сделаете, но это всего лишь вывод на мой счет: -)

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

Использование D.I.C. вы можете настроить, какие классы реализуют определенные интерфейсы, а затем просто заставить его создать экземпляр для вас, он внедрит зависимости в класс.

var processor = Container.Resolve<ZipProcessor>();

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

Наконец, при модульном тестировании вы можете передать имитированные зависимости. Когда вы тестируете свой ZipProcessor, ваши поддельные сервисы будут просто утверждать, что класс пытался отправить электронное письмо, а не пытался его отправить.

//Mock the ZIP
var mockZipService = MockRepository.GenerateMock<IZipService>();
mockZipService.Expect(x => x.Zip("Hello.xml", "Hello.zip"));

//Mock the email send
var mockEmailService = MockRepository.GenerateMock<IEmailService>();
mockEmailService.Expect(x => x.SendEmailTo(.................);

//Test the processor
var testSubject = new ZipProcessor(mockZipService, mockEmailService);
testSubject.Process("Hello.xml");

//Assert it used the services in the correct way
mockZipService.VerifyAlLExpectations();
mockEmailService.VerifyAllExceptions();

Итак, вкратце. Вы хотели бы сделать это, чтобы 01: Не позволяйте потребителям явно знать, какой провайдер реализует необходимые им услуги, а это значит, что при чтении кода сразу становится меньше понимания. 02: Упростить модульное тестирование.

Пит

0 голосов
/ 03 февраля 2009

Вы должны прочитать о PRISM в .NET (рекомендуется создавать составные приложения в .NET). В этих рекомендациях каждый модуль «выставляет» свой тип реализации внутри общего контейнера. Таким образом, каждый модуль имеет четкую ответственность за то, «кто обеспечивает реализацию для этого интерфейса». Думаю, будет достаточно ясно, когда вы поймете, как работает ПРИЗМА.

0 голосов
/ 03 февраля 2009

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

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

...