IoC, куда ты кладешь контейнер? - PullRequest
24 голосов
/ 21 сентября 2008

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

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

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

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

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


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

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

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

Ответы [ 7 ]

11 голосов
/ 30 сентября 2008

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

Это усложняет код, усложняет его тестирование, поддержку, повторное использование и чтение.

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

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

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

Я бы порекомендовал посмотреть мини-сериал Ника Блумхардта по этому вопросу.

http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

3 голосов
/ 21 сентября 2008

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

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

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

2 голосов
/ 23 сентября 2008

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

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

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

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

1 голос
/ 22 октября 2008

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

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

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

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

1 голос
/ 12 октября 2008

В последующем до @ flipdoubt

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

Удачи.

0 голосов
/ 23 апреля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...