Этот вопрос использует Unity в качестве примера, но сам вопрос может касаться любой инфраструктуры IoC DI.
Чтение документации Unity и чтение рекомендаций для модульных тестов, а также опыт работы с моими прошлыми компаниями, я видел, что есть два, казалось бы, несовместимых шаблона проектирования для настройки Unity и IoC:
- Оберните IoC в одноэлементном классе. Официальные примеры Unity, а в некоторых ответах SO есть некоторый статический одноэлементный класс
DependencyFactory
, в котором вы храните контейнер IoC, и в любом месте модуля можно использовать ваш singleton API для разрешения зависимостей, в которых они нуждаются. - Передайте контейнер IoC в функцию. Раннее место, над которым я работал, сделал это, когда почти все функции принимали
IUnityContainer
непосредственно в качестве параметра. Я также видел сообщения о модульном тестировании, предлагающие устанавливать зависимости в параметрах, чтобы явно показывать, на что зависит код.
Эти два, похоже, не согласны, и я не уверен, какой из них считается лучше. Для модульного тестирования, №2 было намного проще, когда я работал в своей старой компании, потому что мне не нужно было беспокоиться об изменении каких-либо синглонов - я просто передал именно то, что было необходимо, и мы закончили. Кроме того, зависимости очень заметны, если у вас есть функция, запрашивающая IDateTimeProvider
как параметр вместо того, чтобы просто получать ее из синглтона в другом месте. Unit test сообщения в блоге, такие как этот показывают примеры непосредственного прохождения в контейнере.
Однако, # 1 намного проще для целей разработки из-за того, насколько он доступен. Это делает его очень легким из любого места в коде, чтобы иметь доступ к чему-либо, и это также, по-видимому, является официальным рекомендуемым способом делать что-то.
Предполагая, что либо выбор # 1, либо # 2, мы завершаем собственный IUnityContainer
в нашем собственном абстрактном API, который, по вашему мнению, лучше - мы имеем наш контейнер IoC в качестве одноэлементного или в качестве параметра we проходят везде? И, если # 1, как мы изменим наши однопользовательские зависимости на основе каждого теста, чтобы получить ту же гибкость управления, которую мы получаем С# 2 для наших модульных тестов и макетов?