Ін'екцыйнае ўвядзенне супраць лакацыйнага абслугоўвання

Фота Джона Карлайла на Unsplash

Шмат якія распрацоўшчыкі там не бачаць розніцы паміж ін'екцыямі залежнасці і мадэлямі канструкцыі лакатара сэрвісу. Так, абодва яны спрабуюць вырашыць адну і тую ж праблему - павялічыць развязку. Мы ўсе ведаем, якія перавагі нам даюць, калі гаворка ідзе пра маштабаванне, праверку або проста чытанне кода.

Аднак як даведацца, калі трэба выкарыстоўваць ін'екцыю залежнасці і калі карыстацца паслугай лакатара? Я б сказаў, што мы павінны выкарыстоўваць абодва, калі гэта дарэчы.

Калі б мне прапанавалі выбраць адзіны дзеяслоў, які найлепшым чынам апісвае схему ўвядзення залежнасці, я б выбраў "даць". Калі вы думаеце пра гэта, то гэта менавіта тое, што мы дасягаем у выніку залежнасці ад залежнасці. Мы проста даем аб'ектам аб'ект.

$ window = новае акно ();
$ door = новая дзверы ();
$ дом = новы дом ($ акно, $ дзверы);

У гэтым выпадку мы аддаем аконны аб'ект і дзвярны прадмет на дом.

З іншага боку, калі б мяне папрасілі апісаць узор службовага лакатара адным дзеясловам, я б сказаў "узяць". Толькі падумайце. Гэта тое, што мы робім, выкарыстоўваючы лакатар сэрвісу. Мы бярэм прадметы з аб'екта.

$ house = $ serviceLocator-> get (Дом :: клас);

Як бачыце, мы бярэм дом з аб'екта абслугоўвання.

У многіх выпадках ін'екцыя залежнасці і лакатар службы працуюць як адзінае цэлае. Мы можам не бачыць гэтага, калі рэчы ўводзяцца аўтаматычна, але за межамі сцэны рэалізацыі ін'екцый залежнасці спадзяюцца на службовыя лакатары, каб знайсці сапраўдныя залежнасці.

Вось як гэта можа выглядаць дзесьці ў кодзе:

foreach ($ залежнасці як $ залежнасць) {
    $ асобнікаў [] = $ this-> container-> get ($ залежнасць);
}
вярнуць $ this-> дазвол ($ class, $ асобнікаў);

Лакатар сэрвісу даволі просты ў рэалізацыі. Усё, што вам трэба, гэта мець магчымасць атрымаць запытаны асобнік па імені альбо ідэнтыфікатару і магчымасць праверыць, ці існуе запытаны асобнік. Варта адзначыць, што лакатар службы часта называюць кантэйнерам. Абедзве рэчы аднолькавыя. Абодва яны прызначаныя для прадастаўлення асобнікаў або паслуг, аднак вы аддасце перавагу называць іх. Канешне, існуе розніца паміж службай і асобнікам, калі казаць пра тэрміны і мэты, але з тэхнічнага пункту гледжання ўсе яны з'яўляюцца асобнікамі пэўных класаў.

Вось прымітыўная версія лакатара службы (ён жа кантэйнер):

клас ServiceLocator {

    прыватныя $ паслугі = [];

    public function get (string $ id):? аб'ект {
        вярнуць $ this-> паслугі [$ id] ?? нулявы;
    }


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

    рэестр публічных функцый (радок $ id, аб'ект $ паслуга): void {
        $ this-> паслугі [$ id] = $ паслуга;
    }
}
$ serviceLocator = новы ServiceLocator ();
$ serviceLocator-> register ('дом', новы дом ());
// дзесьці яшчэ

калі ($ serviceLocator-> has ('house')) {
    $ house = $ serviceLocator-> get ('дом');
}

Дадаткова я прадугледзеў спосаб рэгістрацыі паслуг.

Рэалізацыі ін'екцыі залежнасці звычайна ўводзяць залежнасці ў аб'екты аўтаматычна. Усё, што вам трэба, гэта прадаставіць трохі канфігурацыі, і гэта ўсё. У многіх выпадках гэта вельмі зручна, але бываюць выпадкі, калі вам трэба скарыстацца пошукавым серверам, каб пазбегнуць тупіка. Гэта можа здарыцца, калі два канструкцыі залежаць адзін ад аднаго праз канструктар. Вось прыклад:

клас А {
    
    грамадская функцыя __construct (B $ b)
    {
        //
    }
}

клас Б {
    грамадская функцыя __construct (A $ a)
    {
        //
    }
}
$ a = новы A (...); // Нам трэба Б!
$ b = новы B (...); // Нам трэба А!

Як бачыце, мы не можам дазволіць ні адну з паслуг, паколькі яны залежаць адзін ад аднаго. Мы не можам вырашыць службу A, таму што яна патрабуе службы B, і мы не можам разгадаць сэрвіс B, таму што ён патрабуе службы A. Каб вырашыць гэта, нам трэба аднавіць паслугі лянівым спосабам загрузкі. Гэта значыць, мы павінны ўзяць адну з паслугаў з лакатара сэрвісаў у той момант, калі гэтая паслуга сапраўды неабходная, а не ў канструктары.

Увогуле

Спадзяюся, што гэты артыкул ачысціў некаторыя рэчы для вас, і вам спадабалася яго чытаць. Калі няма, то вы павінны быць ужо разумным праграмістам там ;-)