A függőség befecskendezése

A számítógép-programozásban a dependency injection egy technika, aminek lényege, hogy egy objektum más objektumok függőségeit elégíti ki. A függőséget felhasználó objektum szolgáltatást nyújt, az injekció pedig ennek a függőségnek az átadása a kliens részére. A szolgáltatás a kliens állapotának része.[1] A minta alapkövetelménye a szolgáltatás kliensnek való átadása ahelyett, hogy a szolgáltató objektumot a kliens hozná létre.

A szolgáltató osztály szempontjából ez azt jelenti, hogy a kliens nem hívhat rajta konstruktort, vagy statikus metódust. Paramétereit más osztályoktól kapja, azok állítják be. A függőséget előállítja valaki más, például a kontextus vagy a konténer problémája lesz.

A minta célja, hogy annyira leválassza a szolgáltató objektumot a kliensről, hogy ha kicserélik, akkor ne kelljen módosítani a klienst.

A dependency injection a vezérlés megfordításának egyik formája. Ahelyett, hogy az alacsony szintű kód hívná a magas szintűt, a magas szintű fogadja az alacsony szintűt, amit hívhat. Ez megfordítja a procedurális programozás szokásos vezérlési mintáját.

Ahogy a vezérlés megfordításának többi formája, a dependency injection alkalmazza a felelősség megfordításának elvét. A kliens külső kódnak delegálja függőségeinek létrehozását az injektornak, amit azonban nem hívhat.[2] Fordítva, az injektor hívja a klienst, és adja át neki az objektumot. A kliensnek nem kell tudnia, hogyan kell létrehozni a szolgáltatót, és nem kell tudnia az injektor kódról sem. Csak a szolgáltató interfészét kell ismernie, mert ez definiálja, hogyan hívhatja meg a szolgáltatásokat. Ez elkülöníti egymástól a létrehozás és a használat felelősségét.

A kliens három különböző módon fogadhatja a szolgáltatásokat: szetter, interfész és konstruktor alapú injekcióban. A szetter és a konstruktor injekció abban különbözik, hogy mikor lehet őket használni. Ezektől az interfész alapú injekció abban különbözik, hogy a szolgáltató objektum ellenőrizheti injekcióját. Mindezek megkövetelik, hogy egy külön kód, az injektor hozza létre a kapcsolatot a másik két elem között.[3]

Céljai

A dependency injection a következő problémákat oldja meg:[4]

  • Hogyan lehet az alkalmazás független attól, hogyan hozzák létre az objektumait?
  • Hogyan lehet egy objektum független attól, hogy az általa megkövetelt objektumok hogyan jönnek létre?
  • Hogyan lehet elérni azt, hogy minden objektum tulajdonságait külön konfigurációs fájlban lehessen megadni?
  • Hogyan támogathat az alkalmazás több különböző konfigurációt?

Az objektumok létrehozása a kliens osztályban merevvé teszi a kódot, mivel ezután az objektum csak a megadott osztályú másik objektumot hozhatja létre és használhatja. Lehetetlenné válik, hogy a tartalmazott objektumot kicseréljék a kliens módosítása nélkül. Ez megnehezíti az újrahasználását és a tesztelést is, mert mókolás előtt és után vigyázni kell, hogy most melyik objektumot használjuk, és plusz hibalehetőség adódik.

A dependency injection minta megoldást nyújt erre a problémára:

  • Injektor osztály létrehozása, ami létrehozza és injektálja az objektumokat
  • Az osztály a közvetlen létrehozás helyett az injektortól kapja az objektumokat.

Az osztály így függetlenné válik attól, hogyan hozzák létre a szükséges objektumait, és hogy melyik konkrét osztály tagját használja. A dependency injection miatt az objektumnak nem kell a többi létrehozási mintának (absztrakt gyár, gyártó minta, gyártó metódus, ...) delegálnia az objektum létrehozását. Ez leegyszerűsíti az osztályokat, a megvalósítást, változtatást, tesztelést és újrafelhasználást.[5] design pattern.

Áttekintése

Dependency injection ötéveseknek

Ha kimész a konyhába, és előveszel magadnak valamit enni, akkor problémát okozhatsz. Nyitva hagyhatod az ajtót, elővehetsz valamit, amit a szüleid nem akarnak, hogy megegyél. Olyat kereshetsz, ami nincs bent, vagy elővehetsz valamit, ami meg van romolva.

Ehelyett, ha azt mondod: "Szeretnék valamit enni és inni", akkor biztos lehetsz abban, hogy lesz mit enned és innod, és nem okozol problémát.

John Munsch, 28 October 2009.[6][7][8]

A dependency injection a függőség megfordítása és az egyértelmű felelősség elvét követve[6][9] meglazítja az objektumok közötti csatolást azáltal,[10] hogy elkülöníti a létrehozást és a használatot. Vele szemben áll a szolgáltatáslokátor, ami megengedi a klienseknek, hogy tudomásuk legyen a rendszer egy részéről, hogy megtalálják függőségeiket.

Alapegysége az injekció, ami a paraméterátadáshoz hasonlóan működik.[11] A paraméterátadásra hivatkozva nyilvánvalóvá válik, hogy ez azért van, hogy a klienst elszigetelje a részletektől. Az injekció azt is jelenti, hogy az átadás független a klienstől, és független attól, hogy hogyan valósul meg, érték vagy referencia szerint.

A dependency injection elemei:

  • Szolgáltató objektum
  • Kliens
  • Interfész, amin keresztül a kliens a szolgáltató objektumot látja
  • Injektor, ami létrehozza, beállítja és injektálja a szolgáltató objektumot

A kliens egy objektum, ami igénybe vesz egy másik objektumot. A szolgáltató objektum az, ami szolgáltatást nyújt egy kliens részére. Egy objektum lehet egyszer kliens, másszor szolgáltató objektum.

Az interfész a kliens által elvárt típus. A kliens csak azt láthatja, amit az interfész előír, a szolgáltató objektum többi nyilvános vagy félnyilvános műveletét sem hívhatja. Az interfész lehet interfész, absztrakt osztály vagy konkrét osztály is. Ez utóbbi azonban megsérti a függőség megfordításának elvét,[12] és feláldozza a dinamikus kapcsolatot, ami megkönnyítené a tesztelést. A kliens nem tudhatja, hogy ez pontosan mi, nem tekintheti konkrétnak, nem származtathat belőle vagy hozhat létre saját maga elemet belőle.

A kliens nem ismerheti a szolgáltató objektum konkrét megvalósítását, csak az interfészét és az API-t. A szolgáltató objektum változásai egészen addig nem érintik a klienst, amíg az interfész nem változik. Ha az interfész valódi interfészből osztály lesz vagy megfordítva, akkor a klienst újra kell fordítani.[13] Ez fontos, ha a klienst és a szolgáltató objektumot külön adják ki, például ha egy plugint kell használni.

Az injektor odaadja a szolgáltató objektumot a kliensnek. Gyakran ő is hozza létre és állítja be. Az injektor összekapcsolhat egy bonyolult objektumgráfot azzal, hogy egy objektum hol kliens, hol szolgáltató objektum. Alkothatja több különböző osztályú objektum, de a kliens nem lehet köztük. Az injektorra más neveken is hivatkoznak: assembler, szolgáltató, konténer, gyár, építő, spring, konstrukciós kód vagy main.

A minta alkalmazható architekturális szinten úgy, hogy minden összetett objektum így veszi át részobjektumait. A dependency injection keretrendszer akár be is tilthatja a new kulcsszó használatát, vagy csak érték objektumok létrehozását engedélyezheti.[14][15][16][17]

Taxonómia

A vezérlés megfordítása általánosabb, mint a dependency injection. Az előbbi a Hollywood-elven alapul: Ne hívj, mi hívunk téged. Egy másik példa a sablonfüggvény programtervezési minta, ahol a polimorfizmust öröklődéssel érjük el.[18]

A stratégia programtervezési mintához hasonlóan a dependency injection kompozícióval valósítja meg a vezérlés megfordítását. De míg az az objektum élete alatt is fenntartja a példány kicserélődésének lehetőségét, addig ez többnyire egyetlen példányt használ a kliens életideje alatt.[19] Így a polimorfizmus a kompozícióval és delegációval valósul meg.

Keretrendszerek

Alkalmazás keretrendszerek, mint CDI és megvalósításai Weld, Spring, Guice, Play framework, Salta, Glassfish HK2, Dagger, és Managed Extensibility Framework (MEF) támogatják, de nem teszik kötelezővé a dependency injectiont.[20][21]

Előnyei

  • A dependency injection meghagyja a kliensnek a rugalmasságát a konfiguráció tekintetében. Csak a kliens viselkedése rögzített. A kliens bármivel működik, ami támogatja a kliens által elvárt interfészt.
  • A minta használható arra, hogy a rendszer konfigurációjának részletei konfigurációs fájlokban legyenek megadva, Különböző környezetekhez, helyzetekhez különböző konfigurációs fájlokban különböző konfigurációkat lehet megadni.
  • Mivel nem követeli meg a kliens kód megváltoztatását, alkalmas arra, hogy legacy kódot támogasson. Eredménye az, hogy a kliensek függetlenebbek, ezért egyszerűbb egységteszteket végezni. Dependency injection alkalmazásakor gyakran ez az első előny, amit észrevesznek.
  • A minta lehetővé teszi, sőt megköveteli, hogy a kliensből eltávolítsanak minden tudást, ami az általa használt objektumok konkrét megvalósításának részleteit tartalmazza. Támogatja a karbantarthatóságot és az újrafelhasználhatóságot.[22]
  • Az alkalmazásobjektumokban levő szószátyár kód (boilerplate) csökkenése, mivel az inicializálást és beállítást külön komponens végzi.[22]
  • Segíti a független és a párhuzamos fejlesztést. Az egymást használó osztályok szétoszthatók különböző fejlesztők között, mivel csak egy közös interfészt kell ismerniük. Felhasználhatók olyan pluginok, amelyek fejlesztőivel nem lehetett megbeszélni a részleteket.
  • A minta gyengíti a kapcsolatot a kliens és a szolgáltató objektum között.[23][24]

Hátrányai

  • A kliensek konfigurációs fájlt követelnek, amikor az alapértelmezett értékeknek maguktól kell értődniük. Ez bosszantó lehet, és hibalehetőséget is jelent.
  • A létrehozás és a viselkedés elkülönítése miatt több fájlban kell nyomon kvetelni a rendszer viselkedését. Ez bonyolultabbá teszi a hibák helyének megtalálását.
  • A minta rendszerint a fejlesztés irányát és sorrendjét is megszabja. Ha egy objektum az egységtesztek során megfelelőnek látszik, akkor még azt is igazolni kell, hogy az injekció valóban működik.
  • A bonyolultság a fájlokból átkerül a fájlok rendszerébe, ami nem mindig kívánatos, vagy kezelhető könnyen.[25]
  • A dependency injection arra csábíthatja a fejlesztőket, hogy függjenek egy keretrendszertől.[25][26][27]

Szerkezete

Példa UML osztály- és folyamatdiagram for the Dependency Injection design patterna dependency injection mintáról.[28]

A fenti UML osztálydiagramon a Client osztály nem példányosítja közvetlenül a ServiceA1 és ServiceB1 osztályokat. Neki ServiceA és ServiceB típusú objektumok kellenek, amiket az Injector hoz létre, és injektál a Clientbe. Ezzel a Client függetlenné válik attól, hogyan hozzák létre az általa használt objektumokat, így a konkrét osztályok helyett csak azok általánosításáról tud.

Az UML folyamatdiagram a futásidejű történéseket mutatja: Az Injector létrehozza a ServiceA1 és ServiceB1 osztályú objektumokat. Ezután az Injector létrehozza a Clientet is, és odaadja neki a ServiceA és ServiceB osztályú objektumokat.

Példa

Közvetlen példányosítás

A következő Java példában a Client osztály egyik mezőjében tartalmaz egy Service osztályú objektumot, amit a Client konstruktora inicializál. A Client dönti el, hogy melyik megvalósítást használja, és ellenőrzi a konstrukciós folyamatot. Ekkor a Client erősen függ a ServiceExample osztálytól.

// An example without dependency injection
public class Client {
    // Internal reference to the service used by this client
    private ServiceExample service;

    // Constructor
    Client() {
        // Specify a specific implementation in the constructor instead of using dependency injection
        service = new ServiceExample();
    }

    // Method within this client that uses the services
    public String greet() {
        return "Hello " + service.getName();
    }
}

Ezzel szemben a dependency injection csak az inicializációt engedi meg, az explicit példányosítást nem.

A dependency injection fajtái

Az osztály legalább háromféleképpen szerezhet referenciát egy külső modulra:[29]

  • konstruktor injekció: a szolgáltató objektumokról a konstruktor gondoskodik.
  • szetter injekció: a szolgáltató objektumot a szetter igényli
  • interfész injekció: a szolgáltató objektumnak van injektáló metódusa, ami injektálja bármely kliensbe, amit megkap paraméterként. A klienseknek meg kell valósítaniuk egy interfészt, ami előír egy szetter metódust, ami fogadja az injekciót.

Keretrendszerek lehetővé tehetnek más formájú dependency injectionöket is.[30]

Teszt keretrendszerekben még azt sem követelik meg, hogy a kliens aktívan fogadja a dependency injectiont, ezzel a legacy kód is tesztelhető. Speciálisan, a tesztek használhatnak reflexiót is, amivel hozzáférhetnek a privát adattagokhoz is, így értékadással fogadhatnak injekciót.[31]

A vezérlés megfordítása nem távolítja el teljesen a függőséget, csak helyettesíti egy másikkal. Ökölszabály, hogy ha egy programozó a kliens kódját látva azonosítani tudja a keretrendszert, akkor a kliens erősen függ a keretrendszertől.

Konstruktor injekció

A kliens konstruktora paraméterként veszi át a szolgáltató objektumot:

// Constructor
Client(Service service) {
    // Save the reference to the passed-in service inside this client
    this.service = service;
}

Szetter injekció

A kliens szetterben veszi át a szolgáltató objektumot, mint paramétert:

// Setter method
public void setService(Service service) {
    // Save the reference to the passed-in service inside this client
    this.service = service;
}

Interfész injekció

A kliens csak az interfészt adja meg a szolgáltató objektumokat beállító függvények számára. Meghatározhatja, hogyan beszélhet az injektor a klienshez injektáláskor.

// Service setter interface.
public interface ServiceSetter {
    public void setService(Service service);
}

// Client class
public class Client implements ServiceSetter {
    // Internal reference to the service used by this client.
    private Service service;

    // Set the service that this client is to use.
    @Override
    public void setService(Service service) {
        this.service = service;
    }
}

Konstruktor injekció összehasonlítás

A konstruktor injekció előnyben részesítendő, ha az összes szolgáltató objektum megkonstruálható a kliensnél korábban. Ezzel biztosítható, hogy a kliens állapota mindig érvényes legyen. Ezzel szemben hiányzik az a rugalmassága, hogy később meg lehessen változtatni a szolgáltató objektumait. Ez lehet az első lépés afelé, hogy a kliens megváltoztathatatlan legyen, ezzel szálbiztossá váljon.

// Constructor
Client(Service service, Service otherService) {
    if (service == null) {
        throw new InvalidParameterException("service must not be null");
    }
    if (otherService == null) {
        throw new InvalidParameterException("otherService must not be null");
    }

    // Save the service references inside this client
    this.service = service;
    this.otherService = otherService;
}

Szetter injekció összehasonlítás

A kliensnek minden szolgáltató objektumához szetter kell, így azok bármikor megváltoztathatók. Ez rugalmasságot biztosít, viszont nehezebb biztosítani, hogy mindig mindegyik szolgáltató objektum rendelkezésre álljon.

// Set the service to be used by this client
public void setService(Service service) {
    if (service == null) {
        throw new InvalidParameterException("service must not be null");
    }
    this.service = service;
}

// Set the other service to be used by this client
public void setOtherService(Service otherService) {
    if (otherService == null) {
        throw new InvalidParameterException("otherService must not be null");
    }
    this.otherService = otherService;
}

Mivel az injekciók függetlenek egymástól, sosem lehet tudni, hogy az injektor végzett-e a beállítással. Egy szolgáltató objektum null maradhat, ha az injektor nem tudta meghívni a szetterét. Emiatt ellenőrizni kell a klienst, mielőtt további használatba adjuk.

// Set the service to be used by this client
public void setService(Service service) {
    this.service = service;
}

// Set the other service to be used by this client
public void setOtherService(Service otherService) {
    this.otherService = otherService;
}

// Check the service references of this client
private void validateState() {
    if (service == null) {
        throw new IllegalStateException("service must not be null");
    }
    if (otherService == null) {
        throw new IllegalStateException("otherService must not be null");
    }
}

// Method that uses the service references
public void doSomething() {
    validateState();
    service.doYourThing();
    otherService.doYourThing();
}

Interfész injekció összehasonlítás

Az interfész injekció előnye, hogy a szolgáltató objektumoknak nem kell tudniuk a kliensekről, habár mindig kapnak referenciát az új kliensre, amivel visszahívják a klienst, és átadják magukat referenciaként. Így a szolgáltató objektumok injektorokká válnak. Az injektáló metódust a szolgáltató objektum interfésze írja elő, és akár egyszerű szetter metódus is lehet.

Még mindig szükség van egy mediátorra, ami bemutatja egymásnak a szolgáltató objektumokat és a klienseket. Ez átvesz egy hivatkozást a kliensre, átadja a szetter interfésznek, ami beállítja a szolgáltató objektumot, ezután visszaadja a szolgáltató objektumnak, ami visszaad egy rá mutató referenciát.

Hogy legyen értéke az interfész injekciónak, a szolgáltató objektumnak további műveleteket is kell végeznie. Ez lehet az, hogy gyárként működik, hogy feloldja a további függőségeket, és részleteket vonatkoztat el a fő közvetítőtől. Végezhet referenciaszámlálást, ebből megtudhatja, hány kliens használja. Ha adatszerkezetben tárolja őket, akkor később injektálhatja őket egy másik példányába.

Összegyűjtési példa

A dependency injection megvalósításának egyik módja az, ha kézzel gyűjtjük össze a szereplőket a mainben:

public class Injector {
    public static void main(String[] args) {
        // Build the dependencies first
        Service service = new ServiceExample();

        // Inject the service, constructor style
        Client client = new Client(service);

        // Use the objects
        System.out.println(client.greet());
    }	
}

A fenti példa kézzel hozza létre az objektumgráfot, és meghívja egy ponton, ezzel elindítva a működést. Fontos megjegyezni, hogy ez az injektor nem tiszta, mert az elindítással használ egy általa létrehozott objektumot. Hasonlít a csak konstruáló ServiceExample-hoz, de keveri a konstrukciót és a kliens felhasználását. Habár ez elkerülhetetlen, nem szabad általánosnak lennie. Ahogy az objektumorientált programozásban van nem objektumorientált main metódus, úgy a dependency injection objektumgráfjának is kell belépési pont, ha lehet, akkor csak egy.

A main függvény a létrehozáshoz használhat különféle létrehozási tervmintákat, mint absztrakt gyár, gyártó metódus, építő. Ezek a minták lehetnek absztraktak, ami már elmozdulás a keretrendszer felé, mivel a konstrukciós kód univerzális.[32]

A keretrendszerek, mint a Spring is létrehozhatja ugyanezeket az objektumokat, és összekapcsolhatja őket, mielőtt még referenciát adna a kliensre. Jegyezzük meg, hogy az alábbi kód meg sem említi a ServiceExample-t:

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Injector {
	public static void main(String[] args) {
		// -- Assembling objects -- //
		BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
		Client client = (Client) beanfactory.getBean("client");

		// -- Using objects -- //
		System.out.println(client.greet());
	}
}

A keretrendszerek azt is lehetővé teszik, hogy a részleteket konfigurációs fájlokba emeljük ki. A fenti kód létrehozza az objektumokat, és a Beans.xml alapján összekapcsolja őket. Létrejön a ServiceExample is, habár csak a konfigurációs fájl említi. A fájlban nagy és összetett objektumgráfot lehet definiálni, és csak a belépési metódust kell explicit hívni, ami ebben az esetben a greet().

 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="service" class="ServiceExample">
    </bean>

    <bean id="client" class="Client">
        <constructor-arg value="service" />        
    </bean>
</beans>

A fenti példában a Client és a Service nem ment át olyan a változásokon, amilyeneket a Spring képes nyújtani, egyszerű POJO-k maradtak.[33][34][35] A példa azt mutatja, hogy a Spring képes összekapcsolni egymásról semmit sem tudó objektumokat. Az annotációkkal a rendszer függetlenebbé válik a Springtől,[26] ami fontos, ha egy szép nap a projektmenedzser kitalálja, hogy át kell térni egy másik keretrendszerre, mert az esetleg többet tud.

A POJO-k tisztán tartása nem érhető el költségek nélkül. Konfigurációs fájlok létrehozása helyett annotációk is bevezethetők, és a Spring elvégzi a többit. A függőségek feloldása egyszerű, ha konvenciókat követnek típus vagy név szerinti illeszkedéssel.[36] Ez a konfiguráció fölötti konvencióválasztás. Lehet amellett is érvelni, hogy a keretrendszer cseréjekor a specifikus annotációk eltávolítása egyszerű,[37] és hogy sok injekció annotáció szabványos.[38][39]

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Injector {
	public static void main(String[] args) {
		// Assemble the objects
		BeanFactory beanfactory = new AnnotationConfigApplicationContext(MyConfiguration.class);
		Client client = beanfactory.getBean(Client.class);

		// Use the objects
		System.out.println(client.greet());
	}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan
static class MyConfiguration {
    @Bean
    public Client client(ServiceExample service) {
        return new Client(service);
    }
}
@Component
public class ServiceExample {
    public String getName() {
        return "World!";
    }
}

Az összegyűjtés összehasonlítása

A különböző injektor megvalósítások (gyárak, szolgáltatáslokátorok, dependency injection konténerek) csak annyiban különböznek egymástól, hogy hol használhatók. Ha a gyárat vagy szolgáltatáslokátort nem a kliens hívja, hanem a main, akkor a main kiváló dependency konténerré válik.

Mivel az injektorról való tudás kikerül a kliensből, az tiszta klienssé válik. Azonban bármely objektum, ami objektumokat használ, tekinthető kliensnek, ami alól a main sem kivétel. A main a dependency injection helyett szolgáltatáslokátort, vagy gyárat használ. Ez nem kerülhető el, mert valahol csak dönteni kell, hogy melyik implementációt használjuk.

Az sem változtat ezen, hogy a függőségeket kiszervezzük konfigurációs fájlokba. A jó tervezés egy helyre gyűjti össze a tudást, a szolgáltatáslokátorral csak ez az egy rész áll közvetlen kapcsolatban, a többi kliens tiszta.

AngularJS példa

Az AngularJS keretrendszerben egy komponens háromféleképpen férhet hozzá függőségeihez:

  • Létrehozza a függőséget, tipikusan a new operátorral.
  • Globális változóra hivatkozva elkéri.
  • Mire a függőséget használnia kell, addigra megkapja valahonnan.

Az első két lehetőség nem a legjobb, mivel szorosan összekapcsolja az egyes elemeket. Ez megnehezíti a függőségek módosítását. Különösen problémás ez a tesztek esetén, hogy erre még külön figyelni kell mókolás előtt és utána is.

A harmadik lehetőség már meglazítja a kapcsolatot, mivel a komponensnek már nem kell tudnia, hogy pontosan mit is használ, vagy hol található. A függőséget egyszerűen átadják az objektumnak.

function SomeClass(greeter) {
  this.greeter = greeter;
}

SomeClass.prototype.doSomething = function(name) {
  this.greeter.greet(name);
}

A példában a SomeClass osztálynak nem kell törődnie azzal, hogy létrehozza vagy megkeresse a greeter objektumot, mert példányosításkor megkapja. Ez kívánatos, de a függőségről való tudást áthelyezi abba a kódba, ami elkészíti a SomeClass példányát. A függőségek létrehozására az AngularJS keretrendszer minden alkalmazást injektorral lát el. Az injektor egy szolgáltatáslokátor, ami a függőségek létrehozásáért és kikereséséért felelős. Példa az injektor használatára:

// Provide the wiring information in a module
var myModule = angular.module('myModule', []);

// Teach the injector how to build a greeter service. 
// Notice that greeter is dependent on the $window service. 
// The greeter service is an object that
// contains a greet method.
myModule.factory('greeter', function($window) {
  return {
    greet: function(text) {
      $window.alert(text);
    }
  };
});

Ez létrehoz egy injektort a myModule objektumai számára. A greeter szolgáltató objektum is lekérhető tőle, amit az AngularJS bootstrap elvégez.

var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');

A függőségek lekérése megoldja a kapcsolat lazítását, de azt is jelenti, hogy az injektort a teljes alkalmazásból el kell tudni érni. Ez megsérti a Demeter-elvet, ami a minimális tudás elve. Ez megszüntethető, ha a dokumentumban deklaráljuk, hogy HTML sablonjainkban a létrehozásért az injektor a felelős, mint például:

<div ng-controller="MyController">
  <button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
  $scope.sayHello = function() {
    greeter.greet('Hello World');
  };
}

Ha az AngularJS lefordítja a HTML-t, akkor feldolgozza az ng-controller direktívát is, és megkéri az injektort, hogy hozza létre a vezérlő példányát, és a tőle függő objektumokat.

injector.instantiate(MyController);

Mindezek a színfalak mögött történnek. Jegyezzük meg, hogy azáltal, hogy az ng-controller megkéri az injektort a példányosításra, a vezérlőnek nem kell tudnia az injektor létezéséről. Ez a legjobb kimenetel. Az alkalmazás csak deklarálja a függőségeket, és nem kell törődnie az injektorral, mert automatikusan megkapja őket. Ezzel a Demeter-elvet is betartja.

Jegyzetek

  1. I.T., Titanium: James Shore: Dependency Injection Demystified. www.jamesshore.com . (Hozzáférés: 2015. július 18.)
  2. HollywoodPrinciple. http://c2.com . (Hozzáférés: 2015. július 19.)
  3. Inversion of Control Containers and the Dependency Injection pattern. (Hozzáférés: 2015. július 18.)
  4. The Dependency Injection design pattern - Problem, Solution, and Applicability. w3sDesign.com . (Hozzáférés: 2017. augusztus 12.)
  5. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley, 87ff. o. (1994). ISBN 0-201-63361-2 
  6. a b Dependency Injection in .NET. Manning Publications, 4. o. (2011. október 1.). ISBN 9781935182504 
  7. Dependency Injection in NET. http://philkildea.co.uk . [2015. július 21-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. július 18.)
  8. How to explain dependency injection to a 5-year-old?. stackoverflow.com . (Hozzáférés: 2015. július 18.)
  9. Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, “Seuss: Decoupling responsibilities from static methods for fine-grained configurability”, Journal of Object Technology, Volume 11, no. 1 (April 2012), pp. 3:1-23
  10. Seemann, Mark: Dependency Injection is Loose Coupling. blog.ploeh.dk . (Hozzáférés: 2015. július 28.)
  11. Passing Information to a Method or a Constructor (The Java™ Tutorials > Learning the Java Language > Classes and Objects). docs.oracle.com . (Hozzáférés: 2015. július 18.)
  12. A curry of Dependency Inversion Principle (DIP), Inversion of Control (IoC), Dependency Injection (DI) and IoC Container - CodeProject. www.codeproject.com . (Hozzáférés: 2015. augusztus 8.)
  13. How to force "program to an interface" without using a java Interface in java 1.6. programmers.stackexchange.com . (Hozzáférés: 2015. július 19.)
  14. To "new" or not to "new"…. [2020. május 13-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. július 18.)
  15. How to write testable code. www.loosecouplings.com . (Hozzáférés: 2015. július 18.)
  16. Writing Clean, Testable Code. www.ethanresnick.com . (Hozzáférés: 2015. július 18.)
  17. Sironi, Giorgio: When to inject: the distinction between newables and injectables - Invisible to the eye. www.giorgiosironi.com . (Hozzáférés: 2015. július 18.)
  18. Inversion of Control vs Dependency Injection. stackoverflow.com . (Hozzáférés: 2015. augusztus 5.)
  19. What is the difference between Strategy pattern and Dependency Injection?. stackoverflow.com . (Hozzáférés: 2015. július 18.)
  20. Dependency Injection != using a DI container. www.loosecouplings.com . (Hozzáférés: 2015. július 18.)
  21. Black Sheep » DIY-DI » Print. blacksheep.parry.org . [2015. június 27-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. július 18.)
  22. a b The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330. jcp.org . (Hozzáférés: 2015. július 18.)
  23. the urban canuk, eh: On Dependency Injection and Violating Encapsulation Concerns. www.bryancook.net . (Hozzáférés: 2015. július 18.)
  24. The Dependency Injection Design Pattern. msdn.microsoft.com . (Hozzáférés: 2015. július 18.)
  25. a b What are the downsides to using Dependency Injection?. stackoverflow.com . (Hozzáférés: 2015. július 18.)
  26. a b Dependency Injection Inversion - Clean Coder. sites.google.com . (Hozzáférés: 2015. július 18.)
  27. Decoupling Your Application From Your Dependency Injection Framework. InfoQ . (Hozzáférés: 2015. július 18.)
  28. The Dependency Injection design pattern - Structure and Collaboration. w3sDesign.com . (Hozzáférés: 2017. augusztus 12.)
  29. Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern - Forms of Dependency Injection. Martinfowler.com, 2004. január 23. (Hozzáférés: 2014. március 22.)
  30. Yan - Dependency Injection Types. Yan.codehaus.org. [2013. augusztus 18-i dátummal az eredetiből archiválva]. (Hozzáférés: 2013. december 11.)
  31. AccessibleObject (Java Platform SE 7). docs.oracle.com . (Hozzáférés: 2015. július 18.)
  32. Riehle, Dirk (2000), Framework Design: A Role Modeling Approach, Swiss Federal Institute of Technology, <http://www.riehle.org/computer-science/research/dissertation/diss-a4.pdf>
  33. Spring Tips: A POJO with annotations is not Plain. [2015. július 15-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. július 18.)
  34. Annotations in POJO – a boon or a curse? | Techtracer. [2019. április 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. július 18.)
  35. Pro Spring Dynamic Modules for OSGi Service Platforms. APress. (Hozzáférés: 2015. július 6.)
  36. Captain Debug's Blog: Is ‘Convention Over Configuration’ Going Too Far?. www.captaindebug.com . (Hozzáférés: 2015. július 18.)
  37. Decker, Colin: What's the issue with @Inject? | Colin's Devlog. blog.cgdecker.com . (Hozzáférés: 2015. július 18.)
  38. Morling, Gunnar: Dagger - A new Java dependency injection framework. Dagger - A new Java dependency injection framework - Musings of a Programming Addict , 2012. november 18. (Hozzáférés: 2015. július 18.)
  39. The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330. www.jcp.org . (Hozzáférés: 2015. július 18.)

Fordítás

  • Ez a szócikk részben vagy egészben a Dependency injection című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.

Read other articles:

東京ディズニーリゾート > 舞浜アンフィシアター プロジェクト 東京ディズニーリゾート 舞浜アンフィシアターMaihama Amphitheater 情報旧名称 シルク・ドゥ・ソレイユ シアター東京完成 2008年6月3日開館 2012年9月1日開館公演 プレミア音楽祭2012収容人員 2,170人客席数 2,170席延床面積 約14,000m²用途 多目的ホール旧用途 シルク・ドゥ・ソレイユ専用の常設劇場運営

 

2015 video gameDragon Age: Inquisition – Jaws of HakkonDeveloper(s)BioWarePublisher(s)Electronic ArtsSeriesDragon AgeEngineFrostbite 3Platform(s)Microsoft WindowsXbox OnePlayStation 3PlayStation 4Xbox 360ReleaseWindows, Xbox OneMarch 24, 2015PS3, PS4, Xbox 360May 26, 2015Genre(s)Action role-playingMode(s)Single-player Dragon Age: Inquisition – Jaws of Hakkon is a downloadable content (DLC) pack developed by BioWare and published by Electronic Arts for the 2014 action role-playing video ga...

 

Pour les articles homonymes, voir 37e régiment. 37e régiment d'infanterie territorial Soldats du régiment en position au nord-est de Saint-Martin (Meurthe-et-Moselle) en août 1916. Création 2 août 1914 Dissolution fin février 1918 Pays France Branche Armée de terre Type Régiment d'infanterie territoriale Rôle Infanterie Garnison Auxerre Guerres Première Guerre mondiale modifier  Le 37e régiment d'infanterie territorial est un régiment d'infanterie de l'Armée ...

Este artículo o sección necesita referencias que aparezcan en una publicación acreditada.Este aviso fue puesto el 20 de febrero de 2019. Consejo de Seguridad Pública LocalizaciónPaís Panamá PanamáInformación generalSede Palacio de Las Garzas, Ciudad de PanamáHistoriaFundación 10 de febrero de 1990[editar datos en Wikidata] El Consejo de Seguridad Pública y Defensa Nacional (C.S.P.D.N.) es el principal servicio de inteligencia de Panamá, creado por el decreto N°38 del 1...

 

Esta página cita fontes, mas que não cobrem todo o conteúdo. Ajude a inserir referências. Conteúdo não verificável pode ser removido.—Encontre fontes: ABW  • CAPES  • Google (N • L • A) (Julho de 2021) Localização do Condado de Van Wert em Ohio. Esta é a lista de lugares históricos do Condado de Van Wert, Ohio, listados no Registro Nacional de Lugares Históricos. Existem seis propriedades do condado listados no Regist...

 

Not to be confused with MacGyver (2016 TV series, season 5). Season of television series MacGyverSeason 5The Right Man When Things Go WrongCountry of originUnited StatesNo. of episodes21ReleaseOriginal networkABCOriginal releaseSeptember 18, 1989 (1989-09-18) –April 30, 1990 (1990-04-30)Season chronology← PreviousSeason 4 Next →Season 6 List of episodes The fifth season of MacGyver, an American television series, began September 18, 1989, and ended on April 30, ...

1980 studio album by David Allan CoeI've Got Something to SayStudio album by David Allan CoeReleasedJune 1980Recorded1976StudioColumbia Studios, Pete's Place in NashvilleGenreCountryLength30:47LabelColumbiaProducerBilly SherrillDavid Allan Coe chronology Spectrum VII(1979) I've Got Something to Say(1980) Invictus (Means) Unconquered(1981) Professional ratingsReview scoresSourceRatingAllmusic [1] I've Got Something to Say is an album released by country musician David Allan Coe. It was...

 

Poem by Lord Byron This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: So, we'll go no more a roving – news · newspapers · books · scholar · JSTOR (January 2020) (Learn how and when to remove this template message) So, we'll go no more a roving So we'll go no more a roving     So late into th...

 

German botanist and naturalist (1796–1830) Location of Cape Mertens Karl Heinrich Mertens (Russian: Андрей Карлович Мертенс, 17 May 1796 – 18 September 1830 Kronstadt), was a German botanist and naturalist, and son of the botanist Franz Carl Mertens. Mertens was aboard the Russian vessel Senyavin under Captain Lieutenant Fedor Petrovich Litke with orders to explore the coasts of Russian America and Asia. This turned out to be one of the most productive voyages of disc...

2015 sports event International sporting eventRugby sevens at the 2015 Pan American GamesVenuesExhibition StadiumDatesJuly 11–12, 2015Competitors72 from 6 nationsMedalists  Canada  United States  Brazil2019» Rugby sevens at the2015 Pan American GamesTournamentmenwomenRostersmenwomenvte The women's tournament of rugby sevens at the 2015 Pan American Games was held in Toronto, Ontario, Canada from July 11 to 12.[1] The rugby sevens competi...

 

Hospital in Greater Accra, GhanaLEKMA HospitalHealth service providerGeographyLocationTeshie, Greater Accra, GhanaLinksWebsitewww.lekmahospital.orgListsHospitals in Ghana The Ledzokuku-Krowor Municipal Assembly (LEKMA) Hospital is a hospital located at Teshie in Accra. It is a government hospital.[1][2][3] References ^ ABOUT US – LEKMA HOSPITAL. Retrieved 2018-12-19. ^ Lekma Hospital. HITA e.V. Retrieved 2018-12-19. ^ LEKMA Hospital brings healthcare closer to the pe...

 

Princess Louise, at Masset, BC, circa 1880. History NamePrincess Louise OwnerHudson's Bay Company; Canadian Pacific Railway, others. RouteSan Francisco Bay, Puget Sound, coastal British Columbia and southeast Alaska In service1869 Out of service1919 (unpowered after 1906) IdentificationCanadian #72682: US #19297 FateSank at Port Alice, British Columbia General characteristics Tonnage971 gross tons. Length180 ft (55 m) Beam30 ft (9 m) Depth12.5 ft (4 m) depth of h...

1955 film The Scarlet CoatTheatrical release posterDirected byJohn SturgesWritten byKarl TunbergProduced byNicholas NayfackStarringCornel WildeMichael WildingGeorge SandersAnne FrancisNarrated byPaul FreesCinematographyPaul C. VogelEdited byBen LewisMusic byConrad SalingerProductioncompanyMetro-Goldwyn-MayerDistributed byMetro-Goldwyn-MayerRelease date July 29, 1955 (1955-07-29) Running time101 minutesCountryUnited StatesLanguageEnglishBudget$1.6 million[1][2]Bo...

 

Romanian poet (1916–1944) Isanos on a postage stamp of Moldova (2011) Grave at Bellu Cemetery Magda Isanos (17 April 1916 – 17 November 1944) was a Romanian poet. Biography Born in Iași, her parents were Mihail Isanos and his wife Elisabeta (née Bălan), doctors at the Costiugeni psychiatric hospital near Chișinău.[1] Elisabeta was the sister of Elena Alistar.[2] After graduating from the Diocesan High School in Chișinău, Magda entered the law faculty of the Universi...

 

Merkið Vexillologisches Symbol: [1] Seitenverhältnis: 8:11 Offiziell angenommen: 5. Juni 1959[1] Die Flagge der Färöer, auf Färöisch Merkið (zu deutsch: Zeichen oder Banner), wurde in ihrer heutigen Form am 5. Juli 1959 offiziell eingeführt. Bei einer Umfrage 2004 gaben 17 % der färöischen Haushalte an, sowohl die Flagge als auch eine Fahnenstange zu besitzen, damit sie öffentlich flaggen können.[2] Inhaltsverzeichnis 1 Beschreibung und Bedeutung 2 Ges...

A map of the Flemish Diamond within Belgium. The municipalities seen as being part of the Flemish Diamond. The Flemish Diamond has a high degree of urban sprawl. The Flemish Diamond (Dutch: Vlaamse Ruit) is the Flemish reference to a network of four metropolitan areas in Belgium, three of which are in the central provinces of Flanders, together with the Brussels Capital Region.[1] It consists of four agglomerations which form the four corners of an abstract diamond shape: Brussels, Gh...

 

Ford Transit Courier2014 Ford Tourneo CourierInformasiProdusenFord OtosanJuga disebutFord Tourneo CourierMasa produksi2014-sekarangPerakitanPabrik Yenikoy, Kocaeli, TurkiBodi & rangkaKelasKendaraan komersial ringanLeisure activity vehicleBentuk kerangka5-door vanTata letakFF layoutPlatformplatform B3 FordMobil terkaitFord B-MaxFord Fiesta VIIDimensiJarak sumbu roda2.489 mm (98,0 in)Panjang4.160 mm (163,8 in)Lebar1.976 mm (77,8 in)Tinggi1.747 mm...

 

American baseball player (1868–1923) Baseball player Willard Mains1889 baseball card of MainsPitcherBorn: (1868-07-07)July 7, 1868North Windham, MaineDied: May 23, 1923(1923-05-23) (aged 54)Bridgton, MaineBatted: LeftThrew: RightMLB debutAugust 3, 1888, for the Chicago White StockingsLast MLB appearanceJune 2, 1896, for the Boston BeaneatersMLB statisticsWin–loss record16–17Earned run average3.53Strikeouts96 Teams Chicago White Stockings (1888) Cincinn...

Nissan Ireland Ltd.TypeSubsidiaryIndustryAutomotiveFounded2 February 1977; 46 years ago (1977-02-02)HeadquartersDublin, IrelandProductsAutomobilesParentNissanWebsitewww.nissan.ie Nissan Ireland Ltd. is the Irish subsidiary of Nissan Motor Company of Japan. With an assembly plant for motor vehicles, it was part of the automotive industry in Ireland.[1] Company history The company was founded in Dublin on 2 February 1977.[2] This was preceded by a relationship ...

 

Mountain range in Asia This article is about a mountain range. For other uses, see Himalaya (disambiguation). The HimalayasThe arc of the Himalayas (also Hindu Kush and Karakorams) showing the eight-thousanders (in red); Indo-Gangetic Plain; Tibetan plateau; rivers Indus, Ganges, and Yarlung Tsangpo-Brahmaputra; and the two anchors of the range (in yellow)Highest pointPeakMount Everest,    Nepal and  ChinaElevation8,848.86 m (29,031.7 ft)Coordinates27°5...

 

Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!