Инжектиране на зависимостта срещу локатор на услуги

Снимка на Джон Карлайл на Unsplash

Много разработчици там не виждат разликата между инжектирането на зависимост и моделите на дизайн на локатора на услугата. Да, и двамата се опитват да решат един и същ проблем - увеличете отделянето. Всички знаем какви ползи ни дават това, когато става въпрос за мащабиране, тестване или просто четене на кода.

Как обаче да разбера кога да използвам инжектиране на зависимост и кога да използвам локатор на услугата? Бих казал, че трябва да използваме и двете, когато е уместно.

Ако бях помолен да избера един глагол, който най-добре описва модела на инжектиране на зависимост, бих избрал „да дам“. Ако мислите за това, точно това постигаме с инжектирането на зависимост в края на краищата. Ние просто даваме обекти на обект.

$ window = нов прозорец ();
$ door = нова врата ();
$ house = нова къща ($ прозорец, $ врата);

В този случай даваме обекта на прозореца и обекта на вратата на обекта къща.

От друга страна, ако ме помолят да опиша модела на локатор на услуги с един глагол, бих казал „да взема“. Просто помисли за това. Това правим, когато използваме локатор на услугата. Взимаме обекти от обект.

$ house = $ serviceLocator-> get (Къща :: клас);

Както можете да видите, ние вземаме обекта на къщата от локатора на услугата.

В много случаи инжекцията на зависимост и локатора на услугата работят като едно цяло. Може да не го видим, когато нещата се инжектират автоматично, но зад сцената реализациите на инжектиране на зависимост разчитат на локатори на услуги, за да извлекат реалните зависимости.

Ето как може да изглежда някъде в кода:

foreach ($ зависимости като $ зависимост) {
    $ instanceces [] = $ this-> контейнер-> get ($ зависимост);
}
върнете $ this-> решимостта ($ class, $ instance);

Локаторът на услуги е доста лесен за изпълнение. Всичко, от което се нуждаете, е да имате възможност да получите искан екземпляр по име или идентификатор и възможност да проверите дали исканият екземпляр наистина съществува. Заслужава да се отбележи, че локализаторът на услуги често се нарича контейнер. И двете неща са еднакви. И двете са предназначени да предоставят инстанции или услуги, но предпочитате да им се обаждате. Разбира се, има разлика между услуга и инстанция, когато говорим за условия и цели, но от техническа гледна точка всички те са случаи на определени класове.

Ето примитивна версия на локатор на услуга (известен още като контейнер):

клас ServiceLocator {

    частни $ услуги = [];

    публична функция get (string $ id):? object {
        върнете $ this-> услуги [$ id] ?? нула;
    }


    публична функция има (string $ id): bool {
        възвръщаемост ($ this-> services [$ id]);
    }

    регистър на публичните функции (низ $ id, обект $ услуга): void {
        $ this-> услуги [$ id] = $ услуга;
    }
}
$ serviceLocator = нов ServiceLocator ();
$ serviceLocator-> register ('къща', нова къща ());
// някъде другаде

ако ($ serviceLocator-> има ('къща')) {
    $ house = $ serviceLocator-> get ('къща');
}

Освен това, аз предоставих начина за регистрация на услуги.

Реализациите на инжектиране на зависимост обикновено инжектират зависимости в обекти автоматично. Всичко, което трябва, е да предоставите малко конфигурация и това е всичко. Това е доста удобно в много случаи, но има случаи, когато трябва да използвате локатор за обслужване, за да избегнете безизходицата. Това може да се случи, когато два случая зависят един от друг чрез конструктор. Ето пример:

клас А {
    
    обществена функция __construct (B $ b)
    {
        //
    }
}

клас Б {
    обществена функция __construct (A $ a)
    {
        //
    }
}
$ a = нов A (...); // Имаме нужда от B!
$ b = нов B (...); // Нуждаем се от А!

Както можете да видите, не можем да разрешим нито една от услугите, защото те зависят една от друга. Не можем да разрешим услугата A, защото тя изисква услугата B и не можем да разрешим услугата B, защото тя изисква услугата A. За да разрешим това, трябва да извлечем една от услугите по мързеливо зареждане. Това означава, че трябва да вземем една от услугите от локатора на услугата в момента, в който услугата е действително необходима, а не в конструктора.

Всичко на всичко

Надявам се тази статия да изчисти някои неща за вас и ви хареса да я четете. Ако не, тогава вече трябва да сте най-умен програмист ;-)