вторник, 24 февраля 2015 г.

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

В этом посте я опишу что такое внедрение зависимостей, зачем оно нужно и покажу на рабочем примере как его использовать.

Начнем с самого понятия, википедия говорит нам следущее:
Цитата
Внедрение зависимости (англ. Dependency injection, DI) — процесс предоставления внешней зависимости программному компоненту.


Проще говоря "внедрение зависимостей" это когда объект не знает о своих зависимостях ничего кроме интерфейса . Но стоит заметить что это самый идеальный вариант, реализация же предполагает возможность ряда допущений.

Классификация

Внедрение зависимостей делится на 4 типа:
1. Внедрение через конструктор (constructor injection)
2. Внедрение через сеттеры (setter injection)
3. Внедрение через свойства (property injection)
4. Внедрение через контейнер (service locator)

Для своих проектов я использую property injection и поэтому в этом посте буду расказывать про него.

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

Простой пример

Что бы стало понятно, приведу простой пример внедрения зависимости через свойство.
<?php

class Object2
{
    
}

class Object1
{
    /**
     * @var Object2
     */
    public $object2;
}

$object1 = new Object1;
$object1->object2 = new Object2;


В данном примере, внедрение зависимость происходит вручную, то есть после того как программист инициализировал объект он должен задать ему зависимости самостоятельно.

Внедрение зависимостей через конфигурацию

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

Контейнер зависимостей будет обладать следующими функциями:
1. Получение и хранение объектов
2. Внедрение зависимосте для объектов

Пример простейшего контейнера зависимостей:
<?php

class Object1
{

    /**
     * @var Object2
     */
    public $object2;

}

class Object2
{
    /**
     * @var Object1
     */
    public $object1;
    
    /**
     * @var Object3
     */
    public $object3;
}

class Object3
{
    /**
     * @var DIContainer
     */
    public $container;
}

class DIContainer
{

    protected $objects = array();
    protected $injections = array();

    public function __construct()
    {
        $this->objects['DIContainer'] = $this;
    }

    public function getObject($className)
    {
        if (!empty($this->objects[$className])) {
            return $this->objects[$className];
        }
        
        $object = $this->objects[$className] = new $className;
        
        foreach ($this->injections[$className] as $property => $injectClassName) {
            $object->{$property} = $this->getObject($injectClassName);
        }
        
        return $object;
    }

    public function setInjections(array $injections)
    {
        $this->injections = $injections;
    }

}

$injections = array(
    'Object1' => array(
        'object2' => 'Object2',
    ),
    'Object2' => array(
        'object1' => 'Object1',
        'object3' => 'Object3',
    ),
    'Object3' => array(
        'container' => 'DIContainer',
    )
);

$container = new DIContainer;
$container->setInjections($injections);
/* @var $object1 Object1 */
$object1 = $container->getObject('Object1');

var_dump($object1->object2->object3->container);


Если запустить пример, то можно увидеть что при получении Object1, автоматически внедрятся зависимости не только в Object1, но и в зависимости зависимостей. Это существенный плюс, ведь нам не придется задумываться о том что какой-то зависимости не хватит своих зависимостей, у нас есть гарантия что все зависимосте зависимостей будут загружены если они были заданы в конфигурационном массиве.

Для чего же нужно внедрение зависимостей

1. Перечисление зависимостей всего проекта в одном месте.
2. Автоматическая загрузка зависимостей у зависимостей.
3. Слабая связаннасть
4. Исключение статики из кода

Комментариев нет:

Отправить комментарий