У чому різниця між шаблоном стратегії та ін’єкцією залежності?


95

Шаблон стратегії та ін’єкція залежності дозволяють нам встановлювати / вводити об’єкти під час виконання. У чому різниця між шаблоном стратегії та ін’єкцією залежності?


Шаблон стратегії може використовувати ін’єкцію залежності
TechWisdom

Відповіді:


107

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

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

Крім того, ви можете передавати стратегії як аргументи методам, тоді як пов'язана з ними концепція введення аргументів методу не є широко поширеною і в основному використовується в контексті автоматизованого тестування.

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

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


Інтерфейс, що використовується в DI лише з однією реалізацією, є дуже поширеним - то що ж таке DI в цьому конкретному випадку?
Калпеш Соні

3
Ця цитата в основному все це пояснює:in a DI scenario it is more unusual that the dependencies of objects change during their lifetimes, while this is not uncommon with Strategy
Сергій Тельшевський

Стратегія: Класи розроблені таким чином, що їх можна налаштувати за допомогою алгоритму під час виконання. DI: Такі класи отримують алгоритм (об’єкт Стратегії), що вводиться під час виконання. З пам'яті шаблонів дизайну GoF на w3sdesign.com .
GFranke

39

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

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

public class DataExporter() {
  XMLFormatter formatter = new XMLFormatter();
}

ви б "ввели" форматор у конструктор:

public class DataExporter {
  IFormatter formatter = null;

  public DataExporter(IDataFormatter dataFormatter) {
    this.formatter = dataFormatter;
  }
}

DataExporter exporter = new DataExporter(new XMLFormatter());

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

На цьому прикладі ви можете побачити різницю: ми завжди плануємо використовувати стратегію зберігання даних, і саме ту, яку ми передаємо (справжній екземпляр БД). Однак при розробці та тестуванні ми хочемо використовувати різні залежності, тому вводимо різні конкременти.


28

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

Було б ризиковано сказати, що DI - це просто перейменований шаблон стратегії, оскільки він починає розмивати те, що насправді є шаблоном стратегії, IMO.


2
Думаю, я розумію вашу суть, але я не можу правильно це сформулювати словами ... Отже, ваша приказка DI - це більше шаблон реалізації, тоді як стратегія - більше шаблон дизайну, і один із способів реалізації стратегії - це DI?
Роберт Гулд,

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

15

Чувак, ін’єкція залежностей є більш загальною закономірністю, і мова йде про залежність від абстракцій, а не конкрементів, і це частина кожного шаблону, але шаблон стратегії є рішенням для більш конкретної проблеми

це визначення з Вікіпедії:

DI:

Введення залежностей (DI) в об’єктно-орієнтоване комп’ютерне програмування є шаблоном проектування з основним принципом відокремлення поведінки від дозволу залежностей. Іншими словами: техніка роз'єднання сильно залежних компонентів програмного забезпечення.

Шаблон стратегії:

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

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


3
Мені особливо подобається частина "чувак" у вашому поясненні. :-)
johey

7

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

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


Приклад стратегії:

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

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


Тепер щодо введення залежності:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Використання:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Зверніть увагу на останні 2 перевірки. Вони використовували загальнодоступні дані в тестовому подвійному, який вводили в тестований клас. Я не міг зробити це з виробничим кодом через принцип приховування даних. Я не хотів, щоб у виробничий код вставляли спеціальний код тестування. Публічні дані мали бути в іншому класі.

Тест-подвійник вводили. Це не просто стратегія, оскільки вона впливає на дані, а не лише на функції.


4

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

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


1

Насправді, введення залежностей також дуже схоже на шаблон Bridge. Для мене (і згідно з визначенням) шаблон Bridge повинен враховувати різні версії реалізації, тоді як шаблон Стратегії - для абсолютно іншої логіки. Але зразок коду виглядає так, ніби він використовує DI. То, можливо, DI - це лише техніка чи реалізація?


0

Стратегія - це арена використання ваших навичок введення залежності. Реальними способами реалізації введення залежності є наступні: -

  1. Події
  2. Файли конфігурації карти єдності / структури (або програмно) тощо.
  3. Методи розширення
  4. Анотація завод візерунок
  5. Інверсія шаблону управління (використовується як стратегією, так і Abstract Factory)

Однак одна річ робить стратегію відокремленою. Як ви знаєте в Unity, коли програма запускається, встановлюються всі залежності, і ми не можемо змінити її далі. Але стратегія підтримує зміну залежності від виконання. Але МИ повинні керувати / вводити залежність, а не відповідальність Стратегії!

Насправді стратегія не говорить про введення залежності. При необхідності це можна зробити через Abstract Factory в рамках стратегії. Стратегія говорить лише про створення сімейства класів з інтерфейсом та «гру» з ним. Під час гри, якщо ми виявимо, що класи знаходяться в іншому рівні, тоді ми повинні вводити це самостійно, але не роботу Стратегії.


0

Якщо ми розглядаємо принципи SOLID - ми використовуємо шаблон стратегії для відкритого закритого принципу та введення залежності для принципу інверсії залежності


1
Я не впевнений, що дотримуюся, чи могли б Ви детальніше розповісти про те, як Стратегія співвідноситься з принципом Відкрито / Закрито та як DI відноситься до DIP?
Адам Паркін,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.