Разница между внедрением зависимости и инверсией зависимости

Существуют два шаблона проектирования, а именно Внедрение зависимостей и Инверсия зависимостей. В сети есть статьи, пытающиеся объяснить разницу. Но необходимость объяснить это более простыми словами все еще существует. Есть кто-нибудь, кто мог бы подойти?

Мне нужно понять это в PHP.

8

Решение

(Примечание. Этот ответ не зависит от языка, хотя в этом вопросе конкретно упоминается PHP, но, будучи незнакомым с PHP, я не предоставил никаких примеров PHP).

Инъекция против Инверсии

  • зависимость впрыскивание является Инверсия контроля техника подачи объекты («зависимости») к классу посредством Шаблон проектирования внедрения зависимостей. Как правило, передача зависимостей через одно из следующих:

    • Конструктор
    • Публичная собственность или поле
    • Общественный сеттер
  • Зависимость инверсия Принцип (DIP) является программным дизайном директива который сводится к двум рекомендациям о отсоединение класса от его конкретных зависимостей:

    1. «Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
    2. «Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Внедрение зависимости

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

Класс, который разработан с Внедрение зависимости в виду может выглядеть так:

// Dependency Injection Example...

class Foo {
// Constructor uses DI to obtain the Meow and Woof dependencies
constructor(fred: Meow, barney: Woof) {
this.fred = fred;
this.barney = barney;
}
}

В этом примере Meow а также Woof обе зависимости введенный через Foo конструктор.

С другой стороны, Foo класс, который предназначен без Внедрение зависимостей может просто создать Meow а также Woof самих экземпляров или, возможно, используют какой-то сервисный локатор / фабрику:

// Example without Dependency Injection...

class Foo {
constructor() {
// a 'Meow' instance is created within the Foo constructor
this.fred = new Meow();

// a service locator gets a 'WoofFactory' which in-turn
// is responsible for creating a 'Woof' instance.
// This demonstrates IoC but not Dependency Injection.
var factory = TheServiceLocator.GetWoofFactory();
this.barney = factory.CreateWoof();
}
}

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


Инверсия зависимостей

Deverdency Inversion — это разделение конкретных классов путем предотвращения их непосредственный ссылки друг на друга.

Примечание. Инверсия зависимости часто более явно выражена в языках программирования со статической типизацией, таких как C # или Java, поскольку эти языки обеспечивают строгую проверку типов для имен переменных. С другой стороны, Deverdency Inversion уже пассивно доступна в динамических языках, таких как Python или JavaScript, поскольку переменные в этих языках не имеют каких-либо особых ограничений типов.

Рассмотрим сценарий на языке со статической типизацией, где классу требуется умение читать записи из базы данных приложения:

class Foo {
reader: SqlRecordReader;

constructor(sqlReader: SqlRecordReader) {
this.reader = sqlReader;
}

doSomething() {
var records = this.reader.readAll();
// etc.
}
}

В приведенном выше примере класса Foo имеет жесткую зависимость от SqlRecordReader, но единственное, что его действительно волнует, это то, что существует метод, называемый readAll() который возвращает несколько записей.

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

Если, как следует из названия, SqlRecordReader содержит базу данных и логику SQL, для любого перехода на микросервисы потребуется Foo класс, чтобы измениться.

Руководство по инверсии зависимостей предполагает, что SqlRecordReader следует заменить на абстракцию, которая обеспечивает только readAll() метод. то есть:

interface IRecordReader {
Records[] getAll();
}

class Foo {
reader: IRecordReader;

constructor(reader: IRecordReader) {
this.reader = reader;
}
}

Согласно DIP IRecordReader является абстракция, и заставляя Foo зависит от IRecordReader вместо SqlRecordReader удовлетворяет требованиям DIP.


Почему рекомендации DIP полезны

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

Во многих случаях косвенность может сделать код проще в обслуживании (исправить ошибки, добавить улучшения), однако:

В этом последнем примере Foo может быть получить SqlRecordReaderили, может быть, SoapRecordReaderили, возможно, FileRecordReaderили, может быть, даже для модульного тестирования MockRecordReader — Дело в том, что он не знает или не заботится о различных возможных реализациях IRecordReader — при условии, конечно, эти реализации соответствуют Принцип замещения Лискова.

Кроме того, он избегает потенциально грязного сценария, когда разработчик, который спешит получить что-то работающее, может подумать о попытке «обмануть» принцип Лискова, унаследовав SoapRecordReader или же FileRecordReader из базового класса SqlRecordReader,

Хуже того, неопытный разработчик может даже изменить SqlRecordReader Сам по себе этот класс имеет логику не только для SQL, но и для конечных точек SOAP, Файловой системы и всего остального, что может понадобиться. (Подобные вещи случаются слишком часто в реальном мире, особенно в плохо поддерживаемом коде, и почти всегда Кодовый запах.)

13

Другие решения

Смотрите эту статью Вот

Автор различает эти два в простых словах. Инъекция зависимости == «Дай мне это» и Инверсия зависимости == «Кто-то позаботится об этом для меня, так или иначе».. В принципе инверсии зависимостей, модуль высокого уровня является владельцем абстракции. Таким образом, детализация (реализация абстракции) зависит от абстракции и, следовательно, зависит от модуля высокого уровня. Зависимость инвертирована! .. Зависимость впрыска отличается. Абстракция не может быть сохранена модулем высокого уровня. Таким образом, абстракция, данная объекту более высокого уровня, может не ограничиваться потребностями модуля высокого уровня.

Инверсия зависимостей:

У вас есть модуль X более высокого уровня и абстракция Y, которая определяется X. Z реализует Y и передается X. Таким образом, Z зависит от X (через абстракцию Y, определенную X).

Внедрение зависимости:

У вас есть модуль X более высокого уровня, которому нужны функциональные возможности A и B. Y — абстракция, которая содержит функциональные возможности A, B и C. Z реализует Y. Поскольку Z реализует Y и, следовательно, имеет функциональные возможности A и B, Z присваивается X. Теперь X зависит от Y.

2

Инъекция зависимости — это один из способов достижения инверсии контроля (которую, я полагаю, вы называете инверсией зависимости), поэтому в действительности они не конкурируют настолько, насколько DI является специализацией IoC. Другие распространенные способы достижения IoC включают использование фабрик или шаблон Service Locator.

1
По вопросам рекламы [email protected]