Vstřikování závislosti vs. Lokátor služeb

Foto: John Carlisle na Unsplash

Mnoho vývojářů tam nevidí rozdíl mezi injekcí závislosti a návrhovými vzory lokátorů služeb. Ano, oba se snaží vyřešit stejný problém - zvýšit oddělení. Všichni víme, jaké výhody nám to přináší, pokud jde o škálování, testování nebo prosté čtení kódu.

Jak však mohu vědět, kdy použít závislost injekci a kdy použít vyhledávač služeb? Řekl bych, že bychom v případě potřeby měli oba použít.

Kdybych byl požádán, abych si vybral jediné sloveso, které nejlépe popisuje vzorec závislosti závislosti, zvolil bych „dát“. Pokud o tom přemýšlíte, je to přesně to, čeho dosáhneme s injekcí závislosti. Jednoduše dáváme objekty předmětu.

$ window = nové okno ();
$ door = new Door ();
$ house = new House ($ window, $ door);

V tomto případě dáme objektu okna objekt okna a dveře.

Na druhou stranu, kdybych byl požádán, abych popsal vzor vyhledávače služeb jediným slovesem, řekl bych „vzít“. Přemýšlej o tom. To děláme, když použijeme vyhledávač služeb. Bereme objekty z objektu.

$ house = $ serviceLocator-> get (House :: class);

Jak vidíte, vezmeme dům z vyhledávače služeb.

V mnoha případech fungují vstřikování závislosti a vyhledávač služeb jako jedna jednotka. Možná to neuvidíme, když se věci vstříknou automaticky, ale za scénou se implementace vstřikování závislostí spoléhají na vyhledávače služeb, aby získaly skutečné závislosti.

Takto by to mohlo vypadat někde v kódu:

foreach ($ závislosti jako $ závislost) {
    $ instance [] = $ this-> container-> get ($ dependence);
}
vrátit $ this-> vyřešit ($ class, $ instance);

Implementace vyhledávače služeb je velmi snadná. Vše, co potřebujete, je schopnost získat požadovanou instanci jménem nebo id a schopnost zkontrolovat, zda požadovaná instance skutečně existuje. Je třeba poznamenat, že vyhledávač služeb se často nazývá kontejner. Obě věci jsou stejné. Oba jsou určeny k poskytování instancí nebo služeb, které jim však chcete raději zavolat. Samozřejmě existuje rozdíl mezi službou a instancí, když mluvíme o termínech a účelech, ale z technického hlediska jsou to všechny případy určitých tříd.

Zde je primitivní verze vyhledávače služeb (tzv. Kontejner):

třída ServiceLocator {

    soukromé $ služby = [];

    veřejná funkce get (řetězec $ id):? object {
        vrátit $ this-> služby [$ id] ?? nula;
    }


    veřejná funkce má (řetězec $ id): bool {
        return isset ($ this-> services [$ id]);
    }

    veřejný registr funkcí (řetězec $ id, objekt $ service): void {
        $ this-> services [$ id] = $ service;
    }
}
$ serviceLocator = new ServiceLocator ();
$ serviceLocator-> register ('dům', nový dům ());
// někde jinde

if ($ serviceLocator-> má ('house')) {
    $ house = $ serviceLocator-> get ('house');
}

Kromě toho jsem poskytl způsob registrace služeb.

Implementace injekce závislosti obvykle injektují závislosti do objektů automaticky. Vše, co potřebujete, je poskytnout trochu konfigurace a to je vše. To je v mnoha případech docela pohodlné, ale existují případy, kdy musíte použít vyhledávač služeb, abyste se vyhnuli zablokování. To by se mohlo stát, když jsou dvě instance vzájemně závislé prostřednictvím konstruktoru. Zde je příklad:

třída A {
    
    veřejná funkce __construct (B $ b)
    {
        //
    }
}

třída B {
    veřejná funkce __construct (A $ a)
    {
        //
    }
}
$ a = nový A (...); // Potřebujeme B!
$ b = nový B (...); // Potřebujeme A!

Jak vidíte, nemůžeme vyřešit žádnou ze služeb, protože jsou na sobě závislé. Nemůžeme vyřešit službu A, protože vyžaduje službu B, a nemůžeme vyřešit službu B, protože vyžaduje službu A. K vyřešení tohoto problému musíme načíst jednu ze služeb líným způsobem. To znamená, že bychom měli vzít jednu ze služeb z lokátoru služeb v okamžiku, kdy je služba skutečně potřebná, a ne ve konstruktoru.

Celkově vzato

Doufám, že tento článek pro vás vyjasnil některé věci a líbilo se vám jej přečíst. Pokud ne, pak už tam musíte být nejchytřejší programátor ;-)