Д.И .: Сколько нужно вводить? - PullRequest
18 голосов
/ 19 января 2011

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

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

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

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

Объекты, которые являются настоящими синглетонами, такие как конфигурация приложения или эти маленькие классы утилит, вы вводите их? Кажется, они вводятся очень часто, единственная причина, по которой они вводятся, кажется, заключается в том, что они позволяют изменить значение для тестирования, но Айенде, похоже, решил проблему другим способом:

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

Ответы [ 3 ]

15 голосов
/ 19 января 2011

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

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

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

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

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

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

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

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

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

3 голосов
/ 19 января 2011

Хорошей отправной точкой является введение изменчивых зависимостей .

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

Относительно чрезмерного внедрения конструктора , это действительно просто признак нарушения SRP: см. Этот связанный вопрос: Как избежать безумия конструктора Dependency Injection?

3 голосов
/ 19 января 2011

Мое эмпирическое правило таково:

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

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

Нужно ли вводить логгеры?

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

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

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

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

...