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


104

Я понимаю преимущества самой инъекции зависимостей. Возьмем, к примеру, Spring. Я также понимаю преимущества других функций Spring, таких как АОП, различных помощников и т. Д. Мне просто интересно, каковы преимущества конфигурации 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 и не могу привести такой пример. И я могу показать отдельные строки, демонстрирующие преимущества hibernate, dwr и других фреймворков, которые я использую.


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


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

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

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

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

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

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

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

mary = new FakeFemale();

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

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


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


21
Наконец-то у кого-то хватило смелости задать этот вопрос. Почему вы действительно хотите избегать перекомпиляции, когда ваша реализация изменяется за счет принесения в жертву (или, по крайней мере, ухудшения) поддержки инструментов / IDE?
Кристиан Клаузер,

3
Похоже, название не совсем правильное. Автор сказал, что с контейнерами IOC все в порядке, но, похоже, возникает проблема с использованием конфигурации XML вместо настройки с помощью кода (и достаточно справедливо). Я бы предложил, возможно, «Каковы преимущества настройки контейнеров IOC с помощью XML или других подходов, не связанных с кодом?»
Орион Эдвардс,

Примеры @Orion, которые я предоставил (с мужчинами и женщинами), не требуют контейнера IOC. Я в порядке с МОК; использование контейнера независимо от того, настроен он с использованием XML или нет, для меня все еще остается открытым вопросом.
Павел Фельдман

@Orion 2: Хотя я использую ту или иную форму IOC в большинстве проектов, некоторые из них извлекают выгоду из контейнера IOC в той же мере, в какой они извлекают выгоду из контейнера назначения переменных или контейнера операторов If - мне часто достаточно просто языка. У меня нет проблем с перекомпиляцией проектов, над которыми я работаю, и с удобным разделением кода инициализации dev / test / production. Так что для меня название подходит.
Павел Фельдман

Я вижу проблему с образцом. Принципы - это услуги Inject, а не данные
Jacek Cz

Ответы:


40

Для меня одна из основных причин использовать IoC (и использовать внешнюю конфигурацию) заключается в двух областях:

  • Тестирование
  • Обслуживание производства

Тестирование

Если вы разделите свое тестирование на 3 сценария (что вполне нормально при крупномасштабной разработке):

  1. Модульное тестирование
  2. Интеграционное тестирование
  3. Тестирование черного ящика

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

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

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

Производство

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

Резюме

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

  • Приложение распространяется на несколько сайтов / клиентов, где среды могут отличаться.
  • Ограниченный контроль разработки / ввод в производственную среду и настройку.
  • Сценарии тестирования.

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

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

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


14

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

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

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

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

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

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

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

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


4
понять преимущества DI. Я не понимаю, какие преимущества добавляет внешняя конфигурация XML по сравнению с конфигурационным кодом, который делает то же самое. Упомянутые вами преимущества предоставляются шаблоном проектирования DI. Вопрос был о преимуществах конфигурации DI по сравнению с простым кодом инициализации.
Павел Фельдман,

> Внешняя конфигурация - это тоже разделение ... Разделение конфигурации - это сердце DI, и это хорошо. И это можно сделать с помощью кода инициализации. Что cfg добавляет по сравнению с кодом инициализации? Мне кажется, что каждая строка cfg имеет соответствующую строку кода инициализации.
Павел Фельдман,

7

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

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

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

Однако конфигурация XML - это моя любимая мозоль ... Я стараюсь избегать ее любой ценой.


5

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

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

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

Я постоянно учитываю то, что большинство людей реализует как код в данные, это делает оставшийся код НАМНОГО чище. Я считаю невероятным, чтобы люди создавали меню в коде, а не в виде данных - должно быть очевидно, что делать это в коде просто неправильно из-за шаблона.


имеет смысл, не думал об этом с этой точки зрения
Павел Фельдман

7
с другой стороны, люди часто идут другим путем и пытаются ввести логику в данные, что означает лишь то, что вы в конечном итоге кодируете свое приложение на некачественном языке программирования
Casebash

@Casebash Это интересная точка зрения - мне был бы очень интересен пример. Я считаю, что все, что я могу перенести в данные, помогает. Я также считаю, что если я сделаю именно то, что вы говорите, язык на самом деле улучшится, потому что это DSL, но даже в этом случае для создания совершенно нового языка требуется серьезное оправдание.
Bill K

1
«Каждый раз, когда вы можете изменить свой код на данные, вы делаете шаг в правильном направлении». Добро пожаловать в антипаттерн Soft Coding.
Raedwald

@Raedwald То, о чем вы говорите, - это экстернализация, которая может быть действительно сложной, если вы не знаете, что делаете (и причину, по которой кто-то некомпетентный попробовал это, потерпел неудачу и назвал это анти-шаблоном) Более положительными примерами могут быть инъекции, итераторы , почти все с аннотациями, все, что инициализируется массивами. Большинство хороших программных структур - это попытка отделить различия в вашем коде и объединить то, что осталось, с помощью чего-то, что можно сгруппировать и лучше управлять.
Bill K

3

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

Например, Spring позволяет вам реализовать интерфейс InitializingBean и добавить метод afterPropertiesSet (вы также можете указать «метод инициализации», чтобы избежать привязки вашего кода к Spring). Эти методы позволят вам гарантировать, что любой интерфейс, указанный в качестве поля в вашем экземпляре класса, настроен правильно при запуске, и тогда вам больше не нужно проверять на нуль свои геттеры и сеттеры (при условии, что вы позволяете своим синглетонам оставаться потокобезопасными. ).

Кроме того, гораздо проще выполнять сложные инициализации с помощью контейнера DI, чем выполнять их самостоятельно. Например, я помогаю использовать XFire (не CeltiXFire, мы используем только Java 1.4). Приложение использовало Spring, но, к сожалению, использовало механизм конфигурации XFire services.xml. Когда Коллекции элементов требовалось объявить, что у нее НОЛЬ или более экземпляров вместо ОДНОГО или нескольких экземпляров, мне приходилось переопределить часть предоставленного кода XFire для этой конкретной службы.

В схеме компонентов Spring есть определенные значения по умолчанию для XFire. Итак, если бы мы использовали Spring для настройки служб, можно было бы использовать bean-компоненты. Вместо этого произошло то, что мне пришлось предоставить экземпляр определенного класса в файле services.xml вместо использования bean-компонентов. Для этого мне нужно было предоставить конструктор и настроить ссылки, объявленные в конфигурации XFire. Реальное изменение, которое мне нужно было сделать, требовало перегрузки одного класса.

Но благодаря файлу services.xml мне пришлось создать четыре новых класса, установив их значения по умолчанию в соответствии с их значениями по умолчанию в файлах конфигурации Spring в их конструкторах. Если бы мы могли использовать конфигурацию Spring, я бы просто сказал:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

Вместо этого это выглядело примерно так:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

Таким образом, в конечном итоге в кодовую базу пришлось добавить четыре дополнительных, в основном бессмысленных класса Java, чтобы добиться эффекта от этого одного дополнительного класса и некоторой простой информации о контейнере зависимостей. Это не «исключение, подтверждающее правило», это ЕСТЬ правило ... обработка причуд в коде намного чище, когда свойства уже предоставлены в контейнере DI, и вы просто меняете их в соответствии с особой ситуацией, что случается чаще всего.


3

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

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

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

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

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

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

+1 для выделения корпоративного аспекта прямо вверху. Иногда тестирование плохо написанного устаревшего кода может быть кошмаром на целый день.
Ричард Ле Мезурье

2

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


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

1
Майк, я ничего не сказал о коде. Мы все знаем, что конфигурация XML - отстой :)
аку

Хм .. как часто вы меняете компоненты без перекомпиляции и для чего? Я понимаю, если кто-то меняет учетные данные БД и не хочет перекомпилировать программу - возможно, он не тот, кто ее разрабатывает. Но я не могу себе представить, чтобы кто-то кроме разработчика менял конфигурацию пружин
Павел Фельдман

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

2

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

<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)


Почему модификация логики без перекомпиляции считается хорошей идеей?
Павел Фельдман,

Я определенно могу сделать HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (Джейн); Так единственная разница в том, что cfg можно изменить без перекомпиляции? Когда обсуждают Spring, это кажется обычным ответом. Зачем?! Почему лучше избегать компиляции?
Павел Фельдман,

Что ж, я могу лучше протестировать код, я могу издеваться над женским объектом.
Пол Уилан,

@Pavel Feldman: потому что, если у вас уже есть приложение, развернутое на клиенте, это проще.
Андрей Рыня

1

В мире .NET большинство фреймворков IoC предоставляют конфигурацию как XML, так и кода.

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


Замечательно, что я, наконец, могу использовать код для того, что он намеревался использовать :) Но зачем мне вообще что-то, кроме языка программирования, чтобы делать такие вещи?
Павел Фельдман

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

1

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

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

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

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

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

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


1

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

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


Это верный момент, но конфигурация пружины часто бывает довольно сложной. Хотя изменить возраст несложно, системному администратору по-прежнему приходится иметь дело с большим xml-файлом, который ему не обязательно полностью понимать. Разве не лучше извлечь часть, которая должна быть настроена, во что-то еще более простое, чем конфигурация Spring XML? Как файл свойств, с одной строкой «age = 23» и не позволять администратору изменять другие детали, такие как имена классов и т. Д., Которые требуют знания внутренней структуры программы.
Павел Фельдман

Недавно я работал над проектом, в котором использовался код Java и XSLT. Команда состояла из людей, которые были сильны в Java (и, возможно, менее комфортно работали с XML и XSLT); и люди, которые очень хорошо работали с XML и XSLT (и менее уверенно работали с Java). Поскольку конфигурацией собиралась управлять вторая группа, имело смысл использовать Spring и иметь конфигурации XML. Другими словами, Spring решил проблему разделения труда в команде. Это не решило «технической» проблемы; в том смысле, что конфигурирование можно было так же легко сделать с помощью кода Java.
Давуд ибн Карим,

Когда «обслуживающий персонал» узнает что-нибудь о необходимости изменения некоторых классов, создаваемых в контейнере внедрения зависимостей? Неужели в предположении, что это должен делать разработчик?
Джимбо

Именно по этой причине имеет смысл извлекать значения конфигурации (например, URL-адрес системы, с которой вы интегрируетесь): персонал службы поддержки редактирует файл свойств или (в худшем случае) XML-файл, скомпилированный класс Java остается прежним.
Миро А.

1

С точки зрения Spring я могу дать вам два ответа.

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

Во-вторых, Spring - это намного больше, чем просто структура DI. Он имеет множество других функций, включая управление транзакциями и АОП. Конфигурация Spring XML сочетает все эти концепции вместе. Часто в одном и том же файле конфигурации я указываю зависимости bean-компонентов, настройки транзакций и добавляю bean-компоненты с привязкой к сеансу, которые фактически обрабатываются с использованием AOP в фоновом режиме. Я считаю, что конфигурация XML обеспечивает лучшее место для управления всеми этими функциями. Я также считаю, что конфигурация на основе аннотаций и конфигурация XML лучше масштабируются, чем конфигурация на основе Java.

Но я понимаю вашу точку зрения и нет ничего плохого в определении конфигурации внедрения зависимостей в Java. Обычно я сам это делаю в модульных тестах и ​​когда работаю над проектом, достаточно маленьким, чтобы я не добавил фреймворк DI. Обычно я не указываю конфигурацию на Java, потому что для меня это тот самый код сантехнического оборудования, от написания которого я стараюсь отказаться, когда я решил использовать Spring. Это предпочтение, но это не означает, что конфигурация XML превосходит конфигурацию на основе Java.


0

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

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


0

Ваш случай очень прост и поэтому не требует контейнера IoC (Inversion of Control), такого как Spring. С другой стороны, когда вы «программируете для интерфейсов, а не для реализации» (что является хорошей практикой в ​​ООП), у вас может быть такой код:

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

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

  • Внешняя конфигурация отображения между интерфейсами и их конкретными реализациями
  • Контейнер IoC решает некоторые сложные вопросы, такие как разрешение сложных графов зависимостей, управление временем жизни компонентов и т. Д.
  • Вы экономите время на кодирование, потому что вы предоставляете сопоставления декларативно, а не в процедурном коде.
  • Принцип инверсии управления позволяет упростить модульное тестирование, поскольку вы можете заменить реальные реализации поддельными (например, заменить базу данных SQL базой данных в памяти)

0

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


-2

Одна из самых привлекательных причин - « голливудский принцип »: не звоните нам, мы вам перезвоним. Компоненту не требуется сам выполнять поиск других компонентов и служб; вместо этого они предоставляются ему автоматически. В Java это означает, что больше нет необходимости выполнять поиск JNDI внутри компонента.

Также намного проще провести модульное тестирование компонента изолированно: вместо того, чтобы предоставить ему фактическую реализацию необходимых ему компонентов, вы просто используете (возможно, автоматически сгенерированные) макеты.


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

На самом деле не отвечает на вопрос
Casebash
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.