Существуют два шаблона проектирования, а именно Внедрение зависимостей и Инверсия зависимостей. В сети есть статьи, пытающиеся объяснить разницу. Но необходимость объяснить это более простыми словами все еще существует. Есть кто-нибудь, кто мог бы подойти?
Мне нужно понять это в PHP.
(Примечание. Этот ответ не зависит от языка, хотя в этом вопросе конкретно упоминается PHP, но, будучи незнакомым с PHP, я не предоставил никаких примеров PHP).
зависимость впрыскивание является Инверсия контроля техника подачи объекты («зависимости») к классу посредством Шаблон проектирования внедрения зависимостей. Как правило, передача зависимостей через одно из следующих:
Зависимость инверсия Принцип (DIP) является программным дизайном директива который сводится к двум рекомендациям о отсоединение класса от его конкретных зависимостей:
Во-первых, Внедрение зависимостей — это не то же самое, что инверсия контроля (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.
Ключевое слово директива — инверсия зависимостей добавляет косвенность к дизайну вашей программы. Очевидный недостаток добавления любого вида косвенности заключается в том, что увеличивается сложность (то есть когнитивная «нагрузка», необходимая человеку, чтобы понять, что происходит).
Во многих случаях косвенность может сделать код проще в обслуживании (исправить ошибки, добавить улучшения), однако:
В этом последнем примере Foo
может быть получить SqlRecordReader
или, может быть, SoapRecordReader
или, возможно, FileRecordReader
или, может быть, даже для модульного тестирования MockRecordReader
— Дело в том, что он не знает или не заботится о различных возможных реализациях IRecordReader
— при условии, конечно, эти реализации соответствуют Принцип замещения Лискова.
Кроме того, он избегает потенциально грязного сценария, когда разработчик, который спешит получить что-то работающее, может подумать о попытке «обмануть» принцип Лискова, унаследовав SoapRecordReader
или же FileRecordReader
из базового класса SqlRecordReader
,
Хуже того, неопытный разработчик может даже изменить SqlRecordReader
Сам по себе этот класс имеет логику не только для SQL, но и для конечных точек SOAP, Файловой системы и всего остального, что может понадобиться. (Подобные вещи случаются слишком часто в реальном мире, особенно в плохо поддерживаемом коде, и почти всегда Кодовый запах.)
Смотрите эту статью Вот
Автор различает эти два в простых словах. Инъекция зависимости == «Дай мне это» и Инверсия зависимости == «Кто-то позаботится об этом для меня, так или иначе».. В принципе инверсии зависимостей, модуль высокого уровня является владельцем абстракции. Таким образом, детализация (реализация абстракции) зависит от абстракции и, следовательно, зависит от модуля высокого уровня. Зависимость инвертирована! .. Зависимость впрыска отличается. Абстракция не может быть сохранена модулем высокого уровня. Таким образом, абстракция, данная объекту более высокого уровня, может не ограничиваться потребностями модуля высокого уровня.
Инверсия зависимостей:
У вас есть модуль 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.
Инъекция зависимости — это один из способов достижения инверсии контроля (которую, я полагаю, вы называете инверсией зависимости), поэтому в действительности они не конкурируют настолько, насколько DI является специализацией IoC. Другие распространенные способы достижения IoC включают использование фабрик или шаблон Service Locator.