Яка практична різниця між стилями введення залежності?


12

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

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

На мою думку, введення конструктора - найінтуїтивніше з усіх, а також інтер'єрне введення - найменше. З іншого боку, введення сеттера є середнім терміном, але чи повинні ви мати можливість змінити екземпляр об'єкта залежності, який ви спочатку ввели? Чи гарантує цей стиль ін'єкцій те, що об'єкт, який потребує залежності, завжди буде його вводити? Я не вірю, але, будь ласка, виправте мене, якщо я помиляюся.


Не впевнений, що ще ви знайшли чи прочитали по дорозі. Я знайшов кілька подібних ниток тут і тут . Я сам новий і мені цікаво відповіді, які ви можете отримати :)

@ user1766760 Ви повинні мені допомогти, то тут, моє запитання про закриття, ще два голоси і це зроблено !!! Проголосуйте питання чи щось таке, я не знаю, що можна зробити, щоб уникнути закриття.
ecampver

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

Можливо, ви хочете трохи розширити питання. Ін'єкція залежності - одна з форм "Інверсія управління". Є альтернативи. Наприклад, корисною, але дозрілою для зловживань є службою розташування.
Ян

Відповіді:


12

Перевага конструктора має те, що він робить залежність явною і змушує клієнта надати примірник. Це також може гарантувати, що клієнт не може змінити примірник пізніше. Один (можливий) мінус - ви повинні додати параметр до свого конструктора.

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

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

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

Часто моєю єдиною причиною проходження двох окремих реалізацій є тестування. У виробництві я можу здати в DataRepository, але в тестуванні я пройшов би в FakeDataRepository. У цьому випадку я зазвичай надаю два конструктори: один без параметрів і інший, який приймає a IDataRepository. Потім у конструкторі, що не має параметрів, я буду ланцюгом виклику до другого конструктора і передаю в a new DataRepository().

Ось приклад в C #:


public class Foo
{
  private readonly IDataRepository dataRepository;

  public Foo() : this(new DataRepository())
  {
  }

  public Foo(IDataRespository dataRepository)
  {
    this.dataRepository = dataRepository;
  }
}

Це відоме як ін'єкція бідної людини у бідну людину. Мені це подобається, тому що у виробничому коді клієнта мені не потрібно повторюватись, маючи кілька повторних тверджень, схожих

var foo = new Foo(new DataRepository());
Однак я все-таки можу пройти альтернативну реалізацію для тестування. Я усвідомлюю, що з ІД бідних чоловіків я сильно кодую свою залежність, але це прийнятно для мене, оскільки я здебільшого використовую DI для тестування.


дякую, це досить близько до того, що я розумію, але все-таки, чи є сценарій, коли ви не можете використовувати конструктор впорскування ?
ecampver

1
Напевно, ви не хотіли б використовувати інжектор конструктора для необов'язкових залежностей. Я не можу придумати жодних інших причин не використовувати його.
jhewlett

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

@jhewlett - це фантастично, я шукав хорошу просту техніку заглушки для тестування одиниць, яка не надто ускладнює моє рішення - і я думаю, що це все :)
Rocklan

2

Відмінності між конструктором та інжектором сетерів уже адекватно описані вище, тому я не буду більше їх деталізувати.

Інтерфейсна ін'єкція - це більш вдосконалена форма ін'єкції, яка корисна, оскільки дозволяє вирішити залежність у той момент, коли вона використовується, а не під час ініціалізації об'єкта, який її використовуватиме. Це дозволяє отримати ряд корисних варіантів:

  • Залежність можна по-різному оцінити до об'єкта, в який вона вводиться; наприклад, ви можете використовувати інтерфейс для введення інтерфейсу, щоб забезпечити об'єкт, для якого існує один сеанс користувача або по потоку для глобального синглтона. Кожен раз, коли об'єкт потребує залежності, він буде викликати метод getter, передбачений рамкою, і це може повертати різні результати залежно від ситуації, в якій він викликаний.

  • Це дозволяє ледачу ініціалізацію - немає потреби в ініціалізації залежності, поки вона не збирається використовувати

  • Це дозволяє завантажувати залежності з кешованої копії, коли вони існують, або реініціалізувати, коли вони відсутні (наприклад, використовуючи на SoftReferenceJava).

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.