[xml] Каковы преимущества контейнеров для инъекций зависимостей?



Answers

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

Язык должен обеспечивать хорошую поддержку как обычных объектно-ориентированных методов программирования, так и поддержки интерфейсов объектов и отражения объектов (например, Java и C #). Хотя вы можете создавать программы с использованием шаблонов DI в системах C ++, отсутствие поддержки рефлексии в правильном языке не позволяет ему поддерживать серверы приложений и другие платформы ДИ и, следовательно, ограничивает выразительность шаблонов DI.

Сильные стороны системы, построенной с использованием шаблонов DI:

  1. Код DI намного проще повторно использовать, поскольку функциональность «зависит» экстраполируется на четко определенные интерфейсы, позволяя отдельным объектам, конфигурация которых обрабатывается подходящей платформой приложений, которая будет подключаться к другим объектам по желанию.
  2. Код DI намного проще протестировать. Функциональность, выражаемая объектом, может быть протестирована в черном ящике, создавая объекты «mock», реализующие интерфейсы, ожидаемые вашей логикой приложения.
  3. Код DI более гибкий. Это врожденно слабо связанный код - до крайности. Это позволяет программисту выбирать и выбирать, как объекты подключаются, основываясь исключительно на их требуемых интерфейсах на одном конце и их выраженных интерфейсах, с другой.
  4. Внешняя (Xml) конфигурация объектов DI означает, что другие могут настраивать ваш код в непредвиденных направлениях.
  5. Внешняя конфигурация также является разделом шаблона озабоченности тем, что все проблемы инициализации объекта и управления взаимозависимостью объектов могут обрабатываться сервером приложений.
  6. Обратите внимание, что внешняя конфигурация не требуется для использования шаблона DI, для простых взаимосвязей часто бывает достаточно небольшого объекта-строителя. Между ними есть гибкость. Объект-строитель не такой гибкий, как внешний вид файла конфигурации. Разработчик системы DI должен взвесить преимущества гибкости по сравнению с удобством, заботясь о том, чтобы мелкий масштаб, управление мелким зерном над конструкцией объекта, выраженное в файле конфигурации, может увеличить путаницу и расходы на обслуживание по линии.

Определенно код DI кажется более громоздким, недостатки в том, что все те файлы XML, которые настраивают объекты, которые должны быть введены в другие объекты, кажутся трудными. Это, однако, точка систем DI. Ваша способность смешивать и сопоставлять объекты кода в виде серии параметров конфигурации позволяет создавать сложные системы, используя сторонний код с минимальным кодированием с вашей стороны.

Пример, приведенный в вопросе, затрагивает только поверхность выразительной мощности, которую может предоставить библиотека с объектно-зависимым объектом. С некоторой практикой и большим количеством самодисциплины большинство практикующих DI находят, что они могут создавать системы, которые имеют 100% -ный охват тестирования кода приложения. Этот один только один является экстраординарным. Это не 100% -ный охват тестирования небольшого приложения нескольких сотен строк кода, но 100% -ный охват тестирования приложений, включающий сотни тысяч строк кода. Я теряю возможность описать любой другой шаблон проектирования, который обеспечивает этот уровень проверки.

Вы правы в том, что приложение из 10-ти строк кода легче понять, чем несколько объектов, а также ряд файлов конфигурации XML. Однако, как и в случае с наиболее мощными шаблонами проектирования, выигрыши обнаруживаются при продолжении добавления новых функций в систему.

Короче говоря, широкомасштабные приложения на основе DI легче отлаживать и легче понять. Хотя конфигурация Xml не проверяется временем компиляции, все приложения, которые этот автор знает, предоставят разработчику сообщения об ошибках, если они попытаются вставить объект, имеющий несовместимый интерфейс, в другой объект. И большинство из них обеспечивают функцию проверки, которая охватывает все известные конфигурации объектов. Это легко и быстро делается путем проверки того, что объект A, который должен быть инъецирован, реализует интерфейс, требуемый объектом B для всех сконфигурированных инъекций объектов.

Question

Я понимаю преимущества самой инъекции зависимости. Возьмем, к примеру, весну. Я также понимаю преимущества других функций Spring, таких как AOP, помощники разных типов и т. Д. Мне просто интересно, каковы преимущества конфигурации XML, такие как:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

по сравнению с простым старым java-кодом, например:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

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

ОБНОВИТЬ:
В случае

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

Как ядро ​​IoC может предположить, какую реализацию myService я хочу ввести, если ее несколько? Если есть только одна реализация данного интерфейса, и я позволяю контейнеру IoC автоматически решать использовать его, он будет прерван после появления второй реализации. И если есть намеренно только одна возможная реализация интерфейса, тогда вам не нужно вводить его.

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

ОБНОВЛЕНИЕ 2:
Я понимаю, что конфигурация IoC может быть изменена без повторной компиляции. Это действительно такая хорошая идея? Я могу понять, когда кто-то хочет изменить учетные данные БД без перекомпиляции - он может быть не разработчиком. В вашей практике, как часто кто-то другой, кроме разработчика, меняет конфигурацию IoC? Я думаю, что для разработчиков нет усилий перекомпилировать этот конкретный класс вместо изменения конфигурации. А для не-разработчиков вы, вероятно, захотите сделать свою жизнь проще и предоставить более простой конфигурационный файл.

ОБНОВЛЕНИЕ 3:

Внешняя конфигурация отображения между интерфейсами и их конкретными реализациями

Что такого хорошего в том, чтобы сделать его extenal? Вы не делаете весь свой код внешним, в то время как вы определенно можете - просто поместите его в файл ClassName.java.txt, прочитайте и скомпилируйте вручную на лету - ничего себе, вы избежали перекомпиляции. Почему следует избегать компиляции ?!

Вы сохраняете время кодирования, потому что вы предоставляете сопоставления декларативно, а не в процедурном коде

Я понимаю, что иногда декларативный подход экономит время. Например, я объявляю только один раз, когда сопоставление между свойством bean и столбцом DB, а спящий режим использует это сопоставление при загрузке, сохранении, построении SQL на основе HSQL и т. Д. Именно здесь работает декларативный подход. В случае Spring (в моем примере) объявление имеет больше строк и имеет ту же выразительность, что и соответствующий код. Если есть пример, когда такое объявление короче кода - я бы хотел его увидеть.

Принцип инверсии принципа управления позволяет легко тестировать устройство, поскольку вы можете заменить реальные реализации фальшивыми (например, заменить базу данных SQL на встроенную память)

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

mary = new FakeFemale();

Я понимаю преимущества DI. Я не понимаю, какие преимущества добавляются внешней конфигурацией XML по сравнению с настройкой кода, который делает то же самое. Я не думаю, что компиляции следует избегать - я собираю каждый день, и я все еще жив. Я думаю, что конфигурация DI является плохим примером декларативного подхода. Декларация может быть полезна, если объявлен один раз И используется много раз по-разному - например, hibernate cfg, где сопоставление свойств bean и столбца DB используется для сохранения, загрузки, построения поисковых запросов и т. Д. Конфигурация Spring DI может быть легко переведена на конфигурирование кода, как и в начале этого вопроса, не так ли? И он используется только для инициализации бина, не так ли? Что означает, что декларативный подход ничего здесь не добавляет, не так ли?

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

ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ:
Ребята, много ответов рассказывают мне об инъекции зависимостей, которые я ЗНАЮ ХОРОШО. Вопрос заключается в цели конфигурации DI вместо инициализации кода. Я склонен думать, что код инициализации короче и яснее. Единственный ответ, который я получил до сих пор на мой вопрос, заключается в том, что он избегает перекомпиляции при изменении конфигурации. Думаю, я должен опубликовать еще один вопрос, потому что это большой секрет для меня, почему в этом случае следует избегать компиляции.




Простота объединения частичных конфигураций в окончательную полную конфигурацию.

Например, в веб-приложениях модель, представление и контроллеры обычно указываются в отдельных файлах конфигурации. Используйте декларативный подход, который вы можете загрузить, например:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

Или загрузите другой пользовательский интерфейс и несколько дополнительных контроллеров:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

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




One of the most appealing reasons is the " Hollywood principle ": don't call us, we'll call you. A component is not required to do the lookups to other components and services itself; instead they are provided to it automatically. In Java, this means that it is no longer necessary to do JNDI lookups inside the component.

It is also lots easier to unit test a component in isolation: instead of giving it an actual implementation of the components it needs, you simply use (possibly auto generated) mocks.




У меня есть ответ

В каждом подходе явно имеются компромиссы, но внешние файлы конфигурации XML полезны для развития предприятия, в котором системы сборки используются для компиляции кода, а не для вашей среды IDE. Используя систему сборки, вы можете захотеть ввести определенные значения в свой код - например, версию сборки (которая может быть болезненной при обновлении вручную при каждом компиляции). Боль больше, когда ваша система сборки вытаскивает код из некоторой системы контроля версий. Изменение простых значений во время компиляции потребует от вас изменения файла, его фиксации, компиляции и последующего возврата каждый раз для каждого изменения. Это не изменения, которые вы хотите зафиксировать в своем управлении версиями.

Другие полезные примеры использования системы сборки и внешних конфигураций:

  • вводя стили / таблицы стилей для одной базы кода для разных сборок
  • вводя различные наборы динамического содержимого (или ссылки на них) для вашей единой базы кода
  • использование контекста локализации для разных построек / клиентов
  • изменение URI веб-сервиса на резервный сервер (когда основной отключается)

Обновление: все приведенные выше примеры касались того, что не обязательно требует зависимости от классов. Но вы можете легко создавать случаи, когда необходим как комплексный объект, так и автоматизация - например:

  • Представьте, что у вас была система, в которой она отслеживала трафик вашего сайта. В зависимости от количества одновременных пользователей он включает / выключает механизм ведения журнала. Возможно, в то время как механизм выключен, на его место ставится объект-заглушка.
  • Представьте, что у вас была система веб-конференций, в которой в зависимости от числа пользователей вы хотите отключить возможность делать P2P в зависимости от количества участников



С весны perspecitve я могу дать вам два ответа.

Сначала конфигурация XML не является единственным способом определения конфигурации. Большинство вещей можно настроить с помощью аннотаций, а вещи, которые должны выполняться с XML, - это конфигурация для кода, который вы не пишете, как пул соединений, который вы используете из библиотеки. Весна 3 включает в себя способ определения конфигурации DI с использованием Java, аналогичный настройке DI, выполненной вручную в вашем примере. Поэтому использование Spring не означает, что вам нужно использовать файл конфигурации на основе XML.

Во-вторых, Spring - это нечто большее, чем просто каркас DI. Он имеет множество других функций, включая управление транзакциями и АОП. Конфигурация Spring XML объединяет все эти концепции вместе. Often in the same configuration file I'm specifying bean dependencies, transaction settings and adding session scoped beans that actually handled using AOP in the background. I find the XML configuration provides a better place to manage all these features. I also feel that the annotation based configuration and XML configuration scale up better than doing Java based configuration.

But I do see your point and there isn't anything wrong with defining the dependency injection configuration in Java. I normally do that myself in unit tests and when I'm working on a project small enough that I haven't added a DI framework. I don't normally specify configuration in Java because to me that's the kind plumbing code that I'm trying to get away from writing when I chose to use Spring. That's a preference though, it doesn't mean that XML configuration is superior to Java based configuration.




Your case is very simple and therefore doesn't need an IoC (Inversion of Control) container like Spring. On the other hand, when you "program to interfaces, not implementations" (which is a good practice in OOP), you can have code like this:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(note that the type of myService is IService -- an interface, not a concrete implementation). Now it can be handy to let your IoC container automatically provide the correct concrete instance of IService during initialization - when you have many interfaces and many implementations, it can be cumbersome to do that by hand. Main benefits of an IoC container (dependency injection framework) are:

  • External configuration of mapping between interfaces and their concrete implementations
  • IoC container handles some tricky issues like resolving complicated dependency graphs, managing component's lifetime etc.
  • You save coding time because you provide mappings declaratively, not in a procedural code
  • Inversion of Control principle allows for easy unit testing because you can replace real implementations with fake ones (like replacing SQL database with an in-memory one)



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

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

Кроме того, XML-файл можно считывать в графический интерфейс или какой-либо другой инструмент и легко манипулировать прагматически. Как бы вы это сделали с примером кода?

Я постоянно факторизую то, что большинство людей будет внедрять в качестве кода в данные, он делает код остальным MUCH clean. Мне кажется немыслимым, что люди создадут меню в коде, а не как данные - должно быть очевидно, что делать это в коде просто неправильно из-за шаблона.




Вы можете сложить новую реализацию для подруги. Поэтому новую женщину можно вводить без перекомпиляции кода.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(Вышеприведенное предполагает, что Female и HotFemale реализуют тот же интерфейс GirlfFriend)




Related