Архитектура. Проектирование

icon picker
DI Внедерение зависимостей

Ссылки

Что такое зависимости и их внедрение

Зависимости

Некоторым функциям или классам требуются какие-то настройки, конфиги(параметры конфигурации) или другие функции\объекты. Поэтому образуется потребность от каких-то данных или функций\объектов. Эта потребность и называется в программировании зависимостью

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

Способ передачи конфигурируемых параметров или необходимых функций\классов(зависимостей) снаружи кода. То есть клиентский код получит сразу готовые данные, а не будет их сам создавать
Внедрение зависимостей (DI, Dependency Injection) – это механизм передачи классу его зависимостей. Существует несколько конкретных видов или паттернов внедрения зависимостей: внедрение зависимости через конструктор (), через метод () и через свойство ().
Очень важно понимать, что DI-паттерны не говорят, что за зависимость передается, к какому уровню она относится, должна ли быть она у этого класса или нет. Это лишь инструмент передачи зависимостей от одного класса другому.

Зачем нужно внедрение

Хардкодный пример

Если фукнция требует какой-то объект, то мы можем сразу егго создать в захрдкоренном виде
class A
{
public function a($value) {
$b = new B();
return $b->b($value) * 2;
}
}

Но такой вариант плох тем, что мы не сможем подменить реализацию этого объекта, передать его одну копию на всем проекте и если он требует другие зависимости, то их каждый раз надо будет прописывать при создании.
В случае если зависимость ходит в БД, то мы не сможем подменить ее реализацию и сделать юнит-тест, которому не нужно ходить в БД

Пример с передачей данных для подключения к БД

Пример, где создается класс с ДБ, которому нужно передавать данные для подключения
class A
{
public function a($host, $port, $user, $password) {
$db = new Db($host, $port, $user, $password);
return $db->query('SELECT COUNT (*) FROM users');
}
}

Плохой пример синглтона

class A
{
public function a() {
$db = Db::getInstance();
return $db->query('SELECT COUNT (*) FROM users');
}
}

Здесь мы создаем ДБ через статический “глобальный” метод. И в этом методе нужно как-то передавать параметры конфигурации через глобальные переменные или встроенные константы или хардкодить путь к файлу
Если же потребуются зависимости для такого синглтона, то их тоже надо будет синглтонить. И нет возможности подменить такой синглтон на заглушку какую-нибудь. У него получается есть только один способ себя создать

Правильный пример

Можно передавать зависимость в объект через конструктор
class A
{
public function a(Db $db) {
return $db->query('SELECT COUNT (*) FROM users');
}
}

Или передавать как аргумент функции
class A
{
private Db $db;
public function __conscruct(Db $db) {
$this->db = $db;
}
public function a() {
return $this->db->query('SELECT COUNT (*) FROM users');
}
}

Польза внедрения зависимостей (инверсия зависимостей)

Если зависимость создается снаружи, то клиенскому коду не нужно знать и думать как создать объект и что ему нужно. Они просто указывают название нужного объекта и получают его. Этот контроль ушел наружу, что можно назвать инверсия зависимостей
Эти зависимости теперь можно подменять на заглушки или другие реализации

Сервис-контейнер (Dependency Injection Container, DIC)

DI vs. DIP vs. IoC и что это такое вообще

Разобраться чем отличаются все эти
IoC – Inversion of Control (Инверсия управления)
DI – Dependency Injection (Внедрение зависимостей)
DIP – Dependency Inversion Principle (Принцип инверсии зависимостей)
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.