Подтвердить что ты не робот

IoC, Где вы кладете контейнер?

Я использую виндзор в замке для любимого проекта, над которым я работаю. Я начинаю замечать, что мне нужно вызвать контейнер IoC в разных местах моего кода для создания новых объектов. Эта зависимость от контейнера упрощает мой код.

Есть два решения, которые я использовал для решения этой проблемы.

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

Я использовал основной класс applicationcontroller для переноса контейнера IoC и работы в качестве центрального factory/репозитория. Это было довольно успешным, но этот класс становится слишком большим и действует как центральный объект-бог, почти все другие объекты ссылаются на него.

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


изменить Проблема заключается не в объекте A, который зависит от объекта B. Здесь я обычно использую только инъекцию конструктора, и все работает. Иногда у меня есть объекты типа A, которым необходимо создать переменное количество других объектов типа B в течение их жизни. Я не уверен, как это сделать.

@Blair Конрад: Проблемы с техническим обслуживанием не являются серьезными до сих пор. У меня было несколько классов, зависящих от контейнера-контейнера, вызывающего контейнер. Resolve < > . И я не хочу, чтобы мой код зависел от того, что я считаю инфраструктурой. Я все еще стараюсь, поэтому я заметил, что мне пришлось изменить много кода при переключении с ninject на замок для этого проекта.

@flowers: Хм. Мне нравится решение ваших кулаков. Он сочетает в себе то, что работает с обоими решениями, которые я пробовал. Я думаю, что я все еще слишком много думал об объектах и ​​недостаточно в интерфейсах/обязанностях. Я пробовал целые заводы, но я хотел бы, чтобы они использовали контейнер за кулисами для создания объектов, и я не узнал, как я могу сделать контейнер контейнером чистым способом.

4b9b3361

Ответ 1

Основное преимущество Injection Dependency, по крайней мере, в моих приложениях - это способность писать код, который является агностиком контекста. С этой точки зрения ваше второе решение похоже на то, что оно действительно подрывает выгоду, которую может дать вам DI. Если "объект-бог" предоставляет разные интерфейсы каждому классу, который ссылается на него, он может быть не слишком злым. Но если вы зашли так далеко, я не понимаю, почему вы не добираетесь до обруча.

Пример: ваш объект God имеет метод getFoo() и метод getBar(). Объекту A нужен Foo, для объекта B требуется панель. Если A просто нужен один Foo, Foo следует вводить непосредственно в A, и A вообще не должен знать о Боге. Но если A нужно продолжать создавать Foos, предоставление A ссылки на Бога в значительной степени неизбежно. Но вы можете защитить себя от ущерба, нанесенного Богом, сужая тип ссылки на Бога. Если вы заставляете Бога реализовывать FooFactory и давать ссылку на FooFactory, реализованную Богом, вы все равно можете писать код в нейтральным контекстом. Это улучшает возможности повторного использования кода, и это увеличивает вашу уверенность в том, что изменение к Богу не вызовет неожиданных побочных эффектов. Например, вы можете быть уверены при удалении getBar() от Бога, что класс A не сломается.

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

Ответ 2

Пожалуйста, никогда не используйте статические классы, такие как IoC.Container.Resolve или ContainerFactory.GetContainer!

Это делает код более сложным, сложнее тестировать, поддерживать, повторно использовать и читать.

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

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

Ответ 4

Хотя я ценю объяснение "специально построенных заводов" и даже сам их использую, это похоже на запах кода в моих собственных проектах, потому что публичный интерфейс (маленький "i" ) продолжает меняться с помощью нового factory и/или новый метод GetX для каждой реализации. После прочтения Джереми Миллера Это время для IoC Container Detente, я подозреваю, что дженерики и инъекция самого контейнера - это путь.

Я бы обернул Ninject, StructureMap или Windsor в каком-то интерфейсе IServiceLocator, таком как тот, который предлагается в статье Джереми. Затем добавьте контейнер factory, который просто возвращает IServiceLocator в любом месте вашего кода даже в циклах, как вы изначально предлагали.

IServiceLocator container = ContainerFactory.GetContainer(); 
while( keepLooping )
{
    IExample example = container.GetInstance<IExample>();
    keepLooping = example.DoWork();
}

Контейнер factory всегда может возвращать одно и то же значение, вы можете заменить рамки IoC, что угодно.

Ответ 5

В качестве продолжения @flipdoubt

Если вы в конечном итоге используете шаблон типа локатора службы, вы можете проверить http://www.codeplex.com/CommonServiceLocator. Он имеет некоторые привязки, доступные для нескольких популярных инфраструктур IoC (windsor, structuremap), которые могут быть полезны.

Удачи.

Ответ 6

Я бы рекомендовал в этом случае использовать сильно типизированные фабрики, как вы упомянули, которые вводятся. Эти заводы могут обернуть контейнер, но могут позволить перейти в дополнительный контекст и выполнить дополнительную обработку. Например, Create on the OrderFactory может принимать контекстные параметры.

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

CommonServiceLocator не предназначен для этой цели, хотя может возникнуть соблазн использовать его. Основная цель CommonServiceLocator - это приложения/фреймворки, которые хотят быть совместимыми с контейнером IoC. Тем не менее, приложения, которые используют, должны только вызвать локатор оптимально один раз, чтобы создать иерархию компонентов и их зависимостей. Его никогда нельзя снова называть снова. Если бы у нас был какой-то способ добиться того, что у нас будет. В Prism (http://www.microsoft.com/compositewpf) мы ввели IContainerFacade для создания модулей. Это локатор сервисов, хотя и низкий уровень. В ретроспективе мы, вероятно, должны были создать ModuleFactory или что-то еще и использовать IContianerFacade, чтобы овладеть им, а затем использовать эти модули решения и напрямую обращаться к фасаду. Оглядываясь назад, 20/20. Это достаточно низкий уровень, хотя это действительно не влияет на вещи.

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

Ответ 7

Это действительно проблема сона. Windsor, построенный в Типированный Factory Facility даст вам преимущества использования factory без указанных недостатков.