Localitzador d'injecció de dependència i localitzador de serveis

Foto de John Carlisle a Unsplash

Molts desenvolupadors no veuen la diferència entre la injecció de dependència i els patrons de disseny del localitzador de serveis. Sí, tots dos estan intentant solucionar el mateix problema: augmentar el desacoblament. Tots sabem quins avantatges ens aporta a l’hora d’escalar, provar o simplement llegir el codi.

Tanmateix, com puc saber quan utilitzar la injecció de dependència i quan utilitzar el localitzador de serveis? Diria que hauríem d’utilitzar-los tots dos quan escaigui.

Si se’m demanés que escollís un sol verb que descrigui millor el patró d’injecció de dependència, triaria “donar”. Si hi penses, això és exactament el que aconseguim amb la injecció de dependència al cap i a la fi. Simplement donem objectes a un objecte.

$ window = Finestra nova ();
$ porta = Porta nova ();
$ casa = Casa nova ($ finestra, $ porta);

En aquest cas, donem l’objecte de la finestra i l’objecte de la porta a l’objecte de la casa.

D'altra banda, si se'm demanés que descrivís el patró del localitzador de serveis amb un sol verb, diria "agafar". Penseu-hi. Això és el que fem quan utilitzem un localitzador de serveis. Prenem objectes d’un objecte.

$ casa = $ serveiLocalitzador-> obtenir (Casa :: classe);

Com podeu veure, agafem l’objecte de casa del localitzador de serveis.

En molts casos, la injecció de dependència i el localitzador de serveis funcionen com a unitat única. És possible que no s’ho vegi quan s’injecten les coses de forma automàtica, però darrere dels escenaris les implementacions d’injecció de dependència es basen en localitzadors de serveis per recuperar les dependències reals.

Així pot semblar en algun lloc del codi:

foreach ($ dependències com $ dependència) {
    $ instances [] = $ this-> container-> get ($ dependència);
}
retorna $ this-> resol ($ classe, $ instàncies);

Un localitzador de serveis és bastant fàcil d’implementar. Tot el que necessiteu és tenir capacitat per obtenir una instància sol·licitada per nom o identificador i poder comprovar si realment existeix la instància sol·licitada. Val la pena destacar que un localitzador de serveis s’anomena sovint contenidor. Les dues coses són iguals. Ambdues estan destinades a proporcionar instàncies o serveis, però prefereixes trucar-los. Per descomptat, hi ha una diferència entre un servei i una instància quan es parla de termes i propòsits, però des del punt de vista tècnic, tots són casos de certes classes.

Aquí teniu una versió primitiva d’un localitzador de serveis (aka contenidor):

class ServiceLocator {

    serveis $ privats = [];

    public function get (cadena $ id):? object {
        retorna $ this-> serveis [$ id] ?? nul;
    }


    la funció pública té (cadena $ id): bool {
        retornar isset ($ this-> serveis [$ id]);
    }

    registre de la funció pública (cadena $ id, objecte $ servei): void {
        $ this-> serveis [$ id] = $ servei;
    }
}
$ serviceLocator = nou ServiceLocator ();
$ serviceLocator-> registre ('casa', casa nova ());
// algun altre lloc

if ($ serviceLocator-> has ("casa")) {
    $ casa = $ serveiLocalitzador-> obtenir ("casa");
}

A més, he proporcionat la manera de registrar serveis.

Les implementacions d'injecció de dependència solen injectar automàticament dependències en objectes. Tot el que necessites és proporcionar una mica de configuració i tot això. És força convenient en molts casos, però hi ha casos en què haureu d'utilitzar un localitzador de serveis per evitar el punt mort. Això podria succeir quan dues instàncies depenen les unes de les altres mitjançant el constructor. Aquí teniu un exemple:

classe A {
    
    funció pública __construir (B $ b)
    {
        //
    }
}

classe B {
    funció pública __construir (A $ a)
    {
        //
    }
}
$ a = nou A (...); // Necessitem B!
$ b = nou B (...); // Necessitem A!

Com veieu, no podem resoldre cap dels serveis perquè depenen els uns dels altres. No podem resoldre el servei A perquè requereix el servei B i no podem resoldre el servei B perquè requereix el servei A. Per solucionar-ho, hem de recuperar un dels serveis de manera carregada de mandra. Això vol dir que hauríem de prendre un dels serveis del localitzador de serveis en el punt en què el servei realment es necessita i no del constructor.

En definitiva

Espero que aquest article us hagi esborrat algunes coses i us hagi agradat llegir-lo. Si no és així, haureu de ser el programador més intel·ligent per aquí ;-)