Должен ли я инкапсулировать свой контейнер IoC? - PullRequest
7 голосов
/ 19 ноября 2009

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

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

Чтобы было ясно, я рассматриваю инкапсуляцию регистрации и разрешение типов. Я думаю, что инкапсулировать разрешение не составляет никакого труда - я надеюсь, что обычной практикой будет иметь класс помощника / утилит, делегирующий контейнеру.

EDIT:

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

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

Я ищу:

  • Минимизировать влияние изменений в контейнерах / версиях контейнеров
  • Обеспечение некоторого уровня согласованности регистрации типов между проектами, которые могут использовать разные контейнеры
  • Предоставьте методы интерфейса, которые имеют смысл для меня (RegisterSingleton , а не RegisterType (SomeLifetimeProvider) - на примере Unity).
  • Дополнить контейнер при изменении условий / требований масштабируемости, например, добавление лучшего кэширования, регистрации и т. д. во время разрешения / регистрации.
  • Укажите мою собственную модель для регистрации сопоставлений типов.
    • Допустим, я хочу создать группу объектов RegistrationHandler в сборке / пакете, чтобы я мог легко разделить обязанности по регистрации между несколькими классами и автоматически выбирать эти обработчики, не изменяя код где-либо еще.

Я понимаю, что это немного субъективно, поэтому плюсы и минусы могут быть полезны

Спасибо!

Ответы [ 4 ]

7 голосов
/ 19 ноября 2009

Сделайте это позже, и только если вам действительно нужно поменять контейнеры IOC.

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

Если вам нужно выбрать контейнер IOC, который требует наличия зависимостей от контейнера, выберите тот, который имеет простейший из существующих / API-интерфейс зависимостей. Если вам нужно заменить этот контейнер IOC (а вы, вероятно, не будете), внедрите адаптеры, которые соединяют новый API со старым.

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

EDIT:

Я не вижу иного способа гарантировать безопасность типов:

  1. Разработка относительно сложной реализации шаблона Builder вместе с реализациями посетителей, которые будут записывать файлы конфигурации IOC или что-то эквивалентное.
  2. Реализация DSL с безопасной конфигурацией IOC. (Мой выбор, если у меня было несколько приложений, для которых требовались сменные контейнеры IOC.)
1 голос
/ 14 декабря 2010

Вместо того, чтобы инкапсулировать сам контейнер IOC, я предпочитаю изолировать место взаимодействия с контейнером IOC. Например, в ASP.Net MVC я обычно ограничиваю доступ к контейнеру фабрикой контроллеров и файлом global.aspx.cs, где он обычно устанавливается.

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

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

Для любого из моих приложений замена контейнера IOC по сути была бы вопросом переписывания кода, который конфигурирует контейнер (определяет привязки и т. Д.) И подключает фабрику контроллеров. Для приложений, представленных в виде сервисов, одна и та же базовая идея должна быть разумно управляемой, хотя в зависимости от ограничений вашей среды выполнения вам, возможно, придется использовать внедрение через сеттер, а не через конструктор.

1 голос
/ 19 ноября 2009

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

Если вы считаете, что вам нужна такая гибкость, вы можете взглянуть на проект Common Service Locator на CodePlex. Он делает именно то, что вы ищете: обеспечивает общий фасад для различных контейнеров IoC.

НТН!

1 голос
/ 19 ноября 2009

Да, пойти на это. Это не требует особых усилий и, как вы говорите, обеспечивает лучшую изоляцию от сторонних компонентов.

Это также означает, что вы можете легко отключить контейнер IoC, если найдете что-то лучше. Я недавно сделал это с заменой контейнера Spring.net IoC для Structuremap.

Проект ASP.NET MVC Contrib на codeplex - неплохое место для начала. Это то, на чем я основывал свою реализацию.

...