Які переваги контейнерів для ін'єкційних залежностей?


104

Я розумію самі переваги введення залежності. Візьмемо для прикладу Весну. Я також розумію переваги інших функцій 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:

Зовнішня конфігурація відображення між інтерфейсами та їх конкретними реалізаціями

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

Ви економите час кодування, оскільки надаєте відображення декларативно, а не в процедурному коді

Я розумію, що іноді декларативний підхід економить час. Наприклад, я декларую лише один раз зіставлення між властивістю bean і стовпцем БД і в сплячому режимі використовує це відображення під час завантаження, збереження, побудови SQL на основі HSQL тощо. Тут працює декларативний підхід. У випадку Spring (на моєму прикладі) декларація мала більше рядків і мала таку ж виразність, що і відповідний код. Якщо є приклад, коли така декларація коротша за код - я б хотів її побачити.

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

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

mary = new FakeFemale();

Я розумію переваги DI. Я не розумію, які переваги додає зовнішня конфігурація XML порівняно з конфігураційним кодом, який робить те саме. Я не вважаю, що слід уникати компіляції - я збираю щодня і все ще живу. Я думаю, що конфігурація DI - поганий приклад декларативного підходу. Декларація може бути корисною, якщо оголошується один раз AND використовується багато разів різними способами - наприклад, в сплячому режимі cfg, де відображення між властивістю bean та стовпцем DB використовується для збереження, завантаження, побудови пошукових запитів тощо. Конфігурацію весни DI можна легко перекласти на конфігурація коду, як на початку цього питання, чи не може? І він використовується лише для ініціалізації бобів, чи не так? Що означає декларативний підхід тут нічого не додає, чи не так?

Коли я оголошую сплячу карту, я просто даю сплячку деяку інформацію, і вона працює на її основі - я не кажу їй, що робити. У випадку весни моя декларація каже весною, що саме потрібно робити - то чому б це оголосити, чому б не зробити це?


ОСТАННЕ ОНОВЛЕННЯ:
Хлопці, багато відповідей говорять мені про ін'єкцію залежності, яку я знаю, що це добре. Питання полягає в меті конфігурації DI замість ініціалізації коду - я схильний вважати, що ініціалізація коду коротша і зрозуміліша. Єдиною відповіддю, яку я поки що отримав на своє запитання, є те, що він уникає перекомпіляції, коли змінюється конфігурація. Напевно, я повинен поставити ще одне запитання, оскільки для мене це великий секрет, чому слід уникати компіляції в цьому випадку.


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

3
Здається, що заголовок не зовсім правильний. Автор сказав, що контейнери IOC чудово, але, здається, виникають проблеми з використанням конфігурації XML замість конфігурації за допомогою коду (і досить справедливо). Я б підказав, можливо "Які переваги налаштування контейнерів IOC за допомогою XML або інших підходів без коду?"
Оріон Едвардс

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

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

Я бачу проблеми із зразком. В основі принципів - сервіси ін'єкції, а не дані
Jacek Cz

Відповіді:


40

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

  • Тестування
  • Обслуговування виробництва

Тестування

Якщо ви розділите тестування на 3 сценарії (що є досить нормальним при великомасштабному розвитку):

  1. Блок тестування
  2. Інтеграційне тестування
  3. Тестування чорної скриньки

Що ви хочете зробити, це для останніх двох тестових сценаріїв (Integration & Black box), це не перекомпіляція жодної частини програми.

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

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

Виробництво

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

Підсумок

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

  • Додаток поширюється на кілька сайтів / клієнтів, де середовище буде відрізнятися.
  • Обмежений контроль розвитку / введення над виробничим середовищем та налаштуваннями.
  • Сценарії тестування.

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

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

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


14

Введення залежності - це стиль кодування, коріння якого має коріння у спостереженні, що делегування об'єкта зазвичай є більш корисною схемою дизайну, ніж успадкування об'єкта (тобто об'єкт має - відношення корисніше, ніж об'єкт - відношення). Однак для роботи DI необхідний ще один інгредієнт - створення об'єктних інтерфейсів. Поєднавши ці два потужні шаблони дизайну, інженери програмного забезпечення швидко зрозуміли, що вони можуть створити гнучкий зв'язаний код, і таким чином народилася концепція Dependency Injection. Однак, лише коли відображення об'єктів стало доступним на деяких мовах високого рівня, 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. Маючи певну практику та багато самодисципліни, більшість практиків ДІ виявляють, що вони можуть створювати системи, які мають 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 - але навіть тоді для отримання абсолютно нової мови потрібно серйозне обґрунтування.
Білл К

1
"Ви можете будь-коли змінити свій код на дані, які ви робите крок у правильному напрямку." Ласкаво просимо до анти-шаблону Soft Coding.
Raedwald

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

3

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

Наприклад, Spring дозволяє вам реалізувати інтерфейс InitializingBean та додати метод afterPropertiesSet (ви можете також вказати "init-метод", щоб уникнути прив'язки коду до Spring). Ці методи дозволять вам переконатися, що будь-який інтерфейс, визначений як поле у ​​вашому екземплярі класу, налаштований правильно при запуску, і тоді вам більше не доведеться перевіряти нулі ваших геттерів та сеттерів (якщо припустити, що ви дозволяєте вашим одиночним клавішам залишатися безпечними для потоків ).

Крім того, набагато простіше робити складні ініціалізації з контейнером DI, а не робити їх самостійно. Наприклад, я допомагаю використовувати XFire (не CeltiXFire, ми використовуємо лише Java 1.4). Додаток використовував Spring, але він, на жаль, використовував механізм налаштування XFire's services.xml. Коли колекція елементів, необхідна для того, щоб заявити, що вона має ZERO або більше екземплярів замість ONE або декількох екземплярів, мені довелося перекрити частину наданого коду XFire для цієї конкретної послуги.

У схемі весняних бобів є певні параметри XFire, визначені. Отже, якби ми використовували Spring для налаштування служб, боби можна було б використовувати. Натомість сталося те, що мені довелося надати екземпляр певного класу у файлі services.xml замість використання бобів. Для цього мені потрібно було надати конструктор і встановити посилання, оголошені в конфігурації 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 повинні були бути додані до кодової бази, щоб досягти впливу, який досягнутий додатковий клас та деяка проста інформація про контейнери залежності. Це не "виняток, який підтверджує правило", це IS правило ... обробка диваків в коді набагато чіткіше, коли властивості вже надаються в контейнері DI, і ви просто змінюєте їх відповідно до особливої ​​ситуації, що трапляється частіше, ніж ні.


3

Я маю вашу відповідь

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

Інші корисні випадки використання системи збирання та зовнішніх конфігурацій:

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

Оновлення: Усі наведені вище приклади стосувалися речей, які не обов'язково вимагали залежності від класів. Але ви можете легко створити випадки, коли необхідні і складний об'єкт, і автоматизація - наприклад:

  • Уявіть, у вас була система, в якій вона контролювала трафік вашого веб-сайту. Залежно від кількості одночасних користувачів, він включає / вимикає механізм реєстрації журналу. Можливо, поки механізм вимкнений, на його місце ставиться предмет заглушки.
  • Уявіть, що у вас була система веб-конференцій, в якій залежно від кількості користувачів ви хочете вимкнути можливість робити P2P залежно від # учасників

+1 для виділення аспекту підприємства вгорі. Тестування погано написаного застарілого коду може бути буденним кошмаром часом.
Річард Ле Месюр'є

2

Вам не потрібно перекомпілювати код кожного разу, коли ви щось змінюєте в конфігурації. Це спростить розгортання та обслуговування програми. Наприклад, ви можете поміняти один компонент іншим лише 1 зміною конфігураційного файла.


розгортання? ймовірно ... обслуговування розгортання? ймовірно ... підтримка коду? Я схильний вважати, що ні ... налагодження через рамки, як правило, є великим головним болем, і піхоти набагато простіше вирішити з цього приводу.
Майк Стоун,

1
Майк, я нічого не сказав про код. Всі ми знаємо, що конфігурація XML відстій :)
аку

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

У Павла зазвичай така ситуація виникає, коли вам доведеться розгорнути програму для сотень клієнтів. У такій ситуації набагато простіше змінити конфігурацію, а не розгорнути нову версію продукту. Ти правильно кажеш про чортів. Зазвичай розробник створює новий cfg, а адміністратор розгортає його.
аку

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>

(Вищенаведене передбачає, що жінки та HotF Female реалізують той же інтерфейс GirlfFriend)


Чому зміни логіки без перекомпіляції вважаються хорошою ідеєю?
Павло Фельдман

Я, безумовно, можу зробити HotF Female jane = новий HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Тож єдина різниця в тому, що cfg можна змінити без перекомпіляції? Здається, це звичайна відповідь, коли весна обговорюється. Чому ?! Чому добре уникати компіляції?
Павло Фельдман

Ну я можу краще перевірити код, можу знущатися над жіночим об’єктом.
Пол Уілан

@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 і дозволити, наприклад, системному адміністратору або службі підтримки персоналу змінити значення, не надаючи їм повної потужності над вихідним кодом або іншими налаштуваннями - або просто щоб ізолювати їх від складностей.


Це справедливий момент, але пружинна конфігурація часто має досить складний характер. Хоча легко змінити вік, sysadmin все ще має справу з великим XML-файлом, який він не повинен повністю розуміти. Хіба не краще витягти частину, яка повинна бути налаштована на щось навіть простіше, ніж конфігурація весняного XML? Як і файл властивостей, з одним рядком "age = 23" і не дозволяти адміністратору змінювати інші деталі, наприклад, назви класів тощо, що вимагають знання внутрішньої структури програми.
Павло Фельдман

Я нещодавно працював над проектом, який містив суміш Java-коду та XSLT. Команда представляла собою суміш людей, які сильно працюють на Java (і, можливо, менш комфортно працювати з XML та XSLT); і людей, які дуже сильно працювали з XML та XSLT (і менш зручно з Java). Оскільки конфігурацією керувала друга група, то було сенс використовувати Spring та мати конфігурації XML. Іншими словами, Весна вирішила проблему розподілу праці в колективі. Це не вирішило "технічної" проблеми; в тому сенсі, що конфігу можна було так само легко зробити з кодом Java.
Dawood ibn Kareem

Коли "персонал підтримки" дізнається щось про необхідність змінити деякі класи, створені в контейнері для ін'єкцій залежності? Невже під припущенням, що це робота розробника?
Джимбо

Саме ця причина має значення для вилучення значень конфігурації (наприклад, URL системи, з якою ви інтегруєтесь): підтримка personel редагує файл властивостей або (в гіршому випадку) XML-файл, складений клас Java залишається тим самим.
Миро А.

1

З весняного perspecitve я можу дати вам дві відповіді.

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

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

Але я бачу вашу думку, і немає нічого поганого у визначенні конфігурації ін'єкцій залежності в Java. Я зазвичай роблю це в тестових одиницях, і коли я працюю над проектом досить малим, що я не додав рамки DI. Я зазвичай не вказую конфігурацію в Java, тому що для мене це такий тип сантехнічного коду, який я намагаюся відійти від написання, коли я вирішив використовувати Spring. Це є перевагою, але це не означає, що конфігурація XML перевершує конфігурацію на основі Java.


0

Весна також має властивість навантажувача. Цей метод ми використовуємо для встановлення змінних, які залежать від середовища (наприклад, розробка, тестування, прийняття, виробництво, ...). Це може бути, наприклад, чергу для прослуховування.

Якщо немає причини, за якою властивість змінився б, також немає причин налаштовувати його таким чином.


0

Ваш випадок дуже простий, тому не потрібен контейнер IoC (Інверсія управління), як Spring. З іншого боку, коли ви "програмуєте на інтерфейси, а не на реалізацію" (що є хорошою практикою в OOP), ви можете мати такий код:

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.