Аргументы против Инверсии Контейнеров Контроля - PullRequest
29 голосов
/ 14 апреля 2011

Похоже, все движутся к контейнерам IoC. Я пытался «ухватить» это некоторое время, и, хотя я не хочу быть единственным водителем, который пойдет по неправильному пути на шоссе, это все равно не проходит проверку здравым смыслом для меня. Позвольте мне объяснить, и, пожалуйста, исправьте / просветите меня, если мои аргументы неверны:

Мое понимание: предполагается, что контейнеры IoC облегчат вашу жизнь, комбинируя различные компоненты. Это делается либо через: a) инжекцию конструктора, b) инъекцию сеттера и c) инъекцию интерфейса. Затем они «подключаются» программно или в файле, который читается контейнером. Затем компоненты вызываются по имени, а затем приводятся при необходимости вручную.

Что я не получаю:

РЕДАКТИРОВАТЬ : (лучше формулировка) Зачем использовать непрозрачный контейнер, который не является идиоматическим для языка, если вы можете «связать» приложение (imho) гораздо более простым способом, если компоненты были правильно спроектированы (с использованием шаблонов IoC, слабой связи)? Как этот «управляемый код» приобретает нетривиальную функциональность? (Я слышал некоторые упоминания об управлении жизненным циклом, но я не обязательно понимаю, как это лучше / быстрее, чем «сделай сам».)

ORIGINAL : Зачем идти на все этапы хранения компонентов в контейнере, «связывая их» способами, которые не являются идиоматическими для языка, используя вещи, эквивалентные «меткам goto», когда вы вызываете компоненты по имени, а затем теряете много преимуществ безопасности статически типизированного языка при ручном приведении, когда вы получаете эквивалентную функциональность, не делая этого, и вместо этого используя все интересные функции абстракции, предоставляемые современными языками ОО, например: программирование на интерфейс? Я имею в виду, что части, которые действительно должны использовать компонент под рукой, должны знать, что они используют его в любом случае, и здесь вы будете выполнять «разводку», используя самый естественный идиоматический способ - программирование!

Ответы [ 3 ]

60 голосов
/ 14 апреля 2011

Есть, конечно, люди, которые думают, что DI Containers не приносит никакой пользы , и вопрос правильный. Если вы посмотрите на это исключительно с точки зрения композиции объекта, выгода от контейнера может показаться незначительной. Любая третья сторона может подключить слабосвязанные компоненты.

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

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

Такой инфраструктурный код представляет собой Generic Subdomain , поэтому вполне естественно создать библиотеку многократного использования для решения таких проблем. Это именно то, что DI-контейнер.

Кстати, большинство известных мне контейнеров не используют имена для подключения самих себя - они используют Автоподключение , которое объединяет статическую информацию из Constructor Injection с конфигурацией сопоставлений контейнера от интерфейсов к конкретным классам. Короче говоря, контейнеры изначально понимают эти шаблоны.

Контейнер DI не требуется для DI - он просто чертовски полезен.


Более подробную информацию можно найти в статье Когда использовать DI-контейнер .

7 голосов
/ 14 апреля 2011

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

Использование контейнера IoC - это подмножество инверсии управления , а не все. Вы можете использовать инверсию управления как конструктивную конструкцию, не полагаясь на структуру контейнера IoC. В самом простом случае инверсию управления можно сформулировать в этом контексте как «поставь, а не создавай». Пока ваши объекты внутренне не зависят от реализаций других объектов, а вместо этого требуют, чтобы им были предоставлены реализованные реализации, то вы используете инверсию управления. Даже если вы не используете инфраструктуру контейнера IoC.

Что касается программирования на интерфейс ... Я не уверен, каким был ваш опыт работы с контейнерами IoC (мой личный фаворит StructureMap ), но вы определенно программируете на интерфейс с IoC , Идея, по крайней мере, в том, как я это использовал, заключается в том, что вы отделяете свои интерфейсы (ваши типы) от ваших реализаций (ваших внедренных классов). Код, который опирается на интерфейсы, запрограммирован только для них, и реализации этих интерфейсов внедряются при необходимости.

Например, у вас может быть IFooRepository, который возвращает из экземпляров хранилища данных типа Foo. Весь ваш код, которому нужны эти экземпляры, получает их из предоставленного объекта типа IFooRepository. В другом месте вы создаете реализацию FooRepository и конфигурируете свой IoC для обеспечения того, чтобы везде требовался IFooRepository. Эта реализация может получить их из базы данных, из файла XML, из внешней службы и т. Д. Не имеет значения, где. Этот контроль был инвертирован. Ваш код, который использует объекты типа Foo, не заботится о том, откуда они берутся.

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

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

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

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

2 голосов
/ 10 апреля 2013

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

  1. Способствует кодированию для интерфейса и развязки - Основное преимущество заключается в том, что IOC способствует и облегчает развязку. Вы всегда можете добавить интерфейс в ваш основной объект, а затем использовать методы интерфейса для выполнения задач. Основному объекту не нужно знать, какой зависимый объект назначен интерфейсу. Если вы хотите использовать другой класс в качестве зависимости, все, что вам нужно, это заменить старый класс на новый в файле конфигурации без единой строки изменения кода. Теперь вы можете утверждать, что это может быть сделано в коде с использованием различных шаблонов дизайна интерфейса. Но рамки МОК делают свою прогулку в парке. Таким образом, даже будучи новичком, вы становитесь экспертом в разработке различных шаблонов дизайна интерфейса, таких как мост, фабрика и т. Д.

  2. Чистый код - Поскольку большинство операций создания объекта и жизненного цикла объекта делегируются в контейнер IOC, который вы сохранили из записи повторяющегося кода точки бройлера. Таким образом, у вас есть более чистый, небольшой и понятный код.

  3. Юнит-тестирование - IOC упрощает юнит-тестирование. Поскольку у вас остается отсоединенный код, вы можете легко протестировать отсоединенный код в изоляции. Также вы можете легко внедрить зависимости в ваших тестовых примерах и посмотреть, как взаимодействует другой компонент.

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

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

...