2011-01-19 8 views
15

Я пишу свое второе приложение для реальной жизни, которое использует DI. В целом я думаю, что это позволило улучшить дизайн. Но есть некоторые запахи кода, которые я не знаю, как их решить.DI: Сколько нужно вводить?

Я предпочитаю использовать инъекцию конструктора и часто замечаю, что мне нужно около 5 или более объектов, которые нужно вставить в конструктор. Кажется, слишком много, может быть, это проблема дизайна, а не правильная SRP. Но я думаю, что мое использование ДИ также должно быть обвинено.

Я ищу «лучшие практики» или «эмпирическое правило», в общем, я, кажется, впрыскиваю все, что не в инфраструктуру .Net, это переусердство?

Чтобы начать все, вот два примера объектов, которые я вставляю, но я не уверен.

Объекты, которые являются настоящими синглонами, такими как конфигурация приложения или эти небольшие классы использования, вы их вводите? Они, кажется, очень часто вводятся, единственная причина для их инъекции, похоже, позволяет изменить значение для тестирования, но Айенде, похоже, решил проблему по-другому: http://ayende.com/Blog/archive/2008/07/07/Dealing-with-time-in-tests.aspx.

Общие предметы, такие как ведение журнала, которые используются почти для каждого объекта, должны ли они быть введены?

ответ

3

Мое личное правило заключается в следующем:

  • впрыснуть его, если вы хотите, чтобы быть неизменны
  • вводить его, если вы хотите, чтобы иметь возможность заменить его для целей тестирования

Такие вещи, как услуги, могут соответствовать обоим этим критериям - потребитель никогда не должен его менять, и вы хотите заменить его временем тестирования. С неизменяемыми элементами вы все равно можете иметь свойство на объект-потребителе, но это свойство будет иметь только геттер, а не сеттер. Если вы хотите изменить значение, вы должны создать новый экземпляр объекта.

Должны ли вводиться регистраторы?

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

Следует ли вводить настоящие синглтоны, такие как конфигурация приложения?

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

В то время как DI - хороший образец, слишком хорошая вещь все еще может быть нездоровой. Если вы ощущаете растущий запах кода, изучите каждый предмет, который вы вводите, и задайте себе вопрос: Do i НУЖНО, чтобы ввести этот параметр?

+2

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

12

Правило большого пальца, которое я часто использую, заключается в том, что я ввожу вещи, которые находятся на пути правильной записи модульных тестов. При этом вы иногда заканчиваете абстрагирование классов BCL (например, DateTime.Теперь, файл и т. Д.), А иногда и ваши собственные вещи. Хорошими предложениями являются услуги (такие как ICustomerService, ICustomerUnitOfWorkFactory или ICustomerRepository). Не вводите такие вещи, как сущности, DTO и сообщения.

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

Я предпочитаю использовать инъекции конструктора и часто замечал, что мне нужно около 5 или более объектов, который будет введен в конструкторе.

Как вы уже отметили, наличие многих зависимостей может быть вызвано несоблюдением SRP. Однако вы можете сгруппировать общие зависимости с помощью логики в совокупную услугу и внедрить ее в потребителей. Также см. Статью Марка Семанна о Aggregate Services.

Объекты, истинные одиночек, как конфигурации приложения или те маленьких UTIL классов, вы впрыснуть им?

Я лично не поклонник того, как Айенде предлагает его. Это Ambient Context, который представляет собой особый вид конструкции service locator. Выполнение этого скрывает зависимость, потому что классы могут вызывать этот статический класс без необходимости его вводить. Явное впрыскивание делает его более ясным, что вам нужно время тестирования единицы измерения. Кроме того, это затрудняет запись тестов для таких фреймворков, как MSTest, которые склонны параллельно тестировать тесты. Без каких-либо контрмер, это делает ваши тесты очень ненадежными. Лучшим решением для примера DateTime.Now является наличие интерфейса IClock, как предлагается here. Как вы можете видеть, этот ответ оценивается намного выше, чем подход Айенде, который показан в том же вопросе SO.

Общие объекты, такие, как лесозаготовки, что используются практически в каждом объекте, они должны быть введены?

Я вставляю их в свой код, потому что это делает зависимости ясными. Обратите внимание, однако, что в моем коде мне все равно едва ли нужно вводить регистратор. Подумайте о каждой строке, которую вы хотите зарегистрировать, и это не является провалом (или сквозной проблемой, которая должна быть размещена в другом месте). Обычно я бросаю исключение, когда что-то случилось, чего я не ожидал. Это позволяет мне быстро найти ошибки. Или, другими словами, не фильтровать, а быстро работать. И спросите себя: «Do I log too much?»

Надеюсь, это поможет.

3

Хорошей отправной точкой является введение Volatile Dependencies.

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

Относительно конструктора над закачка, это действительно только симптом нарушения SRP: см этот родственный вопрос: How to avoid Dependency Injection constructor madness?

Смежные вопросы