Gyakran ismételt kérdések a DI-ről (FAQ)
A DI az IoC másik neve?
Az Inversion of Control (IoC) egy olyan elv, amely a kód végrehajtásának módjára összpontosít – arra, hogy
a kódod külső kódot kezdeményez, vagy a kódod integrálódik külső kódba, amely aztán meghívja azt. Az IoC egy tág
fogalom, amely magában foglalja az eseményeket, az úgynevezett hollywoodi elvet és más szempontokat. A gyárak,
amelyek a 3. szabály: Let the Factory Handle It részét
képezik, és a new
operátor inverzióját jelentik, szintén e koncepció összetevői.
A Dependency Injection (DI) arról szól, hogy egy objektum hogyan tud egy másik objektumról, azaz függőségről. Ez egy olyan tervezési minta, amely megköveteli a függőségek explicit átadását az objektumok között.
Így a DI az IoC egy sajátos formájának mondható. Az IoC nem minden formája alkalmas azonban a kódtisztaság szempontjából. Például az anti-minták közé soroljuk az összes olyan technikát, amely globális állapottal vagy az úgynevezett Service Locatorral dolgozik.
Mi az a Service Locator?
A Service Locator a Dependency Injection alternatívája. Úgy működik, hogy létrehoz egy központi tárolót, ahol az összes elérhető szolgáltatás vagy függőség regisztrálva van. Amikor egy objektumnak szüksége van egy függőségre, akkor azt a Service Locatorból kéri.
A Dependency Injectionhoz képest azonban veszít az átláthatóságból: a függőségek nem kerülnek közvetlenül az objektumokhoz, ezért nem könnyen azonosíthatók, ami a kód vizsgálatát igényli az összes kapcsolat feltárásához és megértéséhez. A tesztelés is bonyolultabb, mivel nem adhatunk át egyszerűen mock objektumokat a tesztelt objektumoknak, hanem a Service Locatoron keresztül kell haladnunk. Továbbá a Service Locator megzavarja a kód tervezését, mivel az egyes objektumoknak tisztában kell lenniük a létezésével, ami eltér a Dependency Injectiontől, ahol az objektumok nem tudnak a DI konténerről.
Mikor jobb, ha nem használjuk a DI-t?
A Dependency Injection tervezési minta használatával kapcsolatban nincsenek ismert nehézségek. Ellenkezőleg, a függőségek globálisan elérhető helyekről való megszerzése számos bonyodalomhoz vezet, akárcsak a Service Locator használata. Ezért tanácsos mindig a DI használata. Ez nem dogmatikus megközelítés, de egyszerűen nem találtunk jobb alternatívát.
Vannak azonban olyan helyzetek, amikor nem adunk át objektumokat egymásnak, és a globális térből szerezzük meg őket. Például, amikor kódot hibakeresünk, és a program egy adott pontján ki kell dobnunk egy változó értékét, meg kell mérnünk a program egy bizonyos részének időtartamát, vagy naplóznunk kell egy üzenetet. Ilyen esetekben, amikor olyan ideiglenes műveletekről van szó, amelyek később eltávolításra kerülnek a kódból, jogos egy globálisan elérhető dumper, stopperóra vagy logger használata. Ezek az eszközök végül is nem tartoznak a kód tervezéséhez.
Vannak-e hátrányai a DI használatának?
A Dependency Injection használata jár-e hátrányokkal, például a kódírás bonyolultabbá válásával vagy rosszabb teljesítménnyel? Mit veszítünk, ha a DI-vel összhangban kezdünk kódot írni?
A DI nincs hatással az alkalmazás teljesítményére vagy memóriaigényére. A DI konténer teljesítménye szerepet játszhat, de a Nette DI esetében a konténer tiszta PHP-be van fordítva, így az alkalmazás futási ideje alatt a többletköltsége lényegében nulla.
A kód írásakor olyan konstruktorokat kell létrehozni, amelyek elfogadják a függőségeket. Régebben ez időigényes lehetett, de a modern IDE-knek és a konstruktorok tulajdonságainak promóciójának köszönhetően ez ma már néhány másodperc kérdése. A Nette DI és egy PhpStorm plugin segítségével néhány kattintással könnyedén létrehozhatók a konstruktorok. Másrészt nincs szükség singletonok és statikus hozzáférési pontok írására.
Megállapítható, hogy egy megfelelően megtervezett, DI-t használó alkalmazás nem rövidebb és nem hosszabb a singletonokat használó alkalmazáshoz képest. A függőségekkel dolgozó kódrészek egyszerűen kivonásra kerülnek az egyes osztályokból, és új helyekre, azaz a DI konténerbe és a gyárakba kerülnek.
Hogyan írjunk át egy régi alkalmazást DI-re?
A régebbi alkalmazásról a Dependency Injectionra való áttérés kihívást jelentő folyamat lehet, különösen a nagy és összetett alkalmazások esetében. Fontos, hogy szisztematikusan közelítsük meg ezt a folyamatot.
- A Dependency Injectionra való áttérés során fontos, hogy a csapat minden tagja megértse az alkalmazott elveket és gyakorlatokat.
- Először is végezze el a meglévő alkalmazás elemzését a kulcsfontosságú összetevők és függőségük azonosítása érdekében. Készítsen tervet arra vonatkozóan, hogy mely részeket és milyen sorrendben fogja refaktorálni.
- Implementáljon egy DI-konténert, vagy még jobb, ha egy meglévő könyvtárat használ, például a Nette DI-t.
- Fokozatosan alakítsa át az alkalmazás minden egyes részét a Dependency Injection használatára. Ez magában foglalhatja a konstruktorok vagy metódusok módosítását, hogy paraméterként elfogadják a függőségeket.
- Módosítsa a kód azon helyeit, ahol függőségi objektumok jönnek létre, hogy a függőségeket a konténer injektálja. Ez magában foglalhatja a gyárak használatát.
Ne feledje, hogy a függőségi injektálásra való áttérés a kód minőségébe és az alkalmazás hosszú távú fenntarthatóságába való befektetés. Bár kihívást jelenthet ezeknek a változtatásoknak a végrehajtása, az eredménynek tisztább, modulárisabb és könnyen tesztelhető kódnak kell lennie, amely készen áll a jövőbeli bővítésekre és karbantartásra.
Miért előnyösebb a kompozíció az örökléssel szemben?
Az öröklés helyett előnyösebb a kompozíciót használni, mert ez a kód újrafelhasználását szolgálja anélkül, hogy aggódnunk kellene a változások következményei miatt. Így lazább csatolást biztosít, ahol nem kell aggódnunk amiatt, hogy bizonyos kódok megváltoztatása más függő kódok megváltoztatásának szükségességét eredményezi. Tipikus példa erre a konstruktorpokolnak nevezett helyzet.
Használható-e a Nette DI Container a Nette rendszeren kívül is?
Természetesen. A Nette DI Container része a Nette-nek, de önálló könyvtárként van kialakítva, amely a keretrendszer más részeitől függetlenül használható. Csak telepítse a Composer segítségével, hozzon létre egy konfigurációs fájlt, amely meghatározza a szolgáltatásait, majd néhány sor PHP kóddal hozza létre a DI konténert. És máris elkezdheti kihasználni a Dependency Injection előnyeit a projektjeiben.
A Nette DI Container fejezetben leírja, hogyan néz ki egy konkrét felhasználási eset, a kóddal együtt.
Miért van a konfiguráció NEON fájlokban?
A NEON egy egyszerű és könnyen olvasható konfigurációs nyelv, amelyet a Nette-en belül fejlesztettek ki az alkalmazások, szolgáltatások és függőségeik beállítására. A JSON-hoz vagy a YAML-hez képest sokkal intuitívabb és rugalmasabb lehetőségeket kínál erre a célra. A NEON-ban természetesen leírhatók olyan kötöttségek, amelyeket Symfony & YAML-ben egyáltalán nem vagy csak bonyolult leírással lehetne megírni.
Lassítja a NEON fájlok elemzése az alkalmazást?
Bár a NEON fájlok elemzése nagyon gyorsan történik, ez a szempont nem igazán számít. Ennek oka az, hogy a fájlok elemzése csak egyszer történik meg az alkalmazás első indítása során. Ezt követően a DI-konténer kódja generálódik, a lemezen tárolódik, és minden további kérésnél további elemzés nélkül végrehajtódik.
Ez így működik a termelési környezetben. A fejlesztés során a NEON-fájlok minden alkalommal elemzése megtörténik, amikor tartalmuk megváltozik, így biztosítva, hogy a fejlesztő mindig naprakész DI-konténerrel rendelkezzen. Mint korábban említettük, a tényleges elemzés egy pillanat alatt megtörténik.
Hogyan férhetek hozzá a konfigurációs fájl paramétereihez az osztályomban?
Tartsd szem előtt az 1. szabályt: Hagyd, hogy átadják neked. Ha egy osztálynak szüksége van egy konfigurációs fájlból származó információra, nem kell kitalálnunk, hogyan érhetjük el az információt, hanem egyszerűen kérdezzük meg – például az osztály konstruktorán keresztül. Az átadást pedig a konfigurációs fájlban végezzük el.
Ebben a példában a %myParameter%
a myParameter
paraméter értékének helyőrzője, amelyet a
MyClass
konstruktornak adunk át:
# config.neon
parameters:
myParameter: Some value
services:
- MyClass(%myParameter%)
Ha több paramétert akar átadni, vagy automatikus kapcsolást szeretne használni, hasznos, ha a paramétereket egy objektumba csomagolja.
Támogatja a Nette a PSR-11 konténer interfészt?
A Nette DI Container nem támogatja közvetlenül a PSR-11-et. Ha azonban interoperabilitásra van szüksége a Nette DI Container és a PSR-11 Container interfészt elváró könyvtárak vagy keretrendszerek között, létrehozhat egy egyszerű adaptert, amely hídként szolgál a Nette DI Container és a PSR-11 között.