Pogosto zastavljena vprašanja o DI (FAQ)
- Je DI drugo ime za IoC?
- Kaj je Service Locator?
- Kdaj je bolje DI ne uporabiti?
- Ima uporaba DI svoje slabe strani?
- Kako prenoviti staro aplikacijo na DI?
- Zakaj se daje prednost kompoziciji pred dedovanjem?
- Ali je mogoče uporabiti Nette DI Container zunaj Nette?
- Zakaj je konfiguracija v NEON datotekah?
- Ali razčlenjevanje NEON datotek upočasnjuje aplikacijo?
- Kako iz svojega razreda dostopam do parametrov v konfiguracijski datoteki?
- Ali Nette podpira PSR-11: Container interface?
Je DI drugo ime za IoC?
Inversion of Control (IoC) je načelo, osredotočeno na način, kako se koda izvaja – ali vaša koda izvaja tujo
ali je vaša koda integrirana v tujo, ki jo nato kliče. IoC je širok pojem, ki vključuje dogodke, tako imenovani Hollywoodski princip in druge vidike. Del tega
koncepta so tudi tovarne, o katerih govori Pravilo št. 3: pusti
tovarni, in ki predstavljajo inverzijo za operator new
.
Dependency Injection (DI) se osredotoča na način, kako en objekt izve za drug objekt, torej za njegove odvisnosti. Gre za načrtovalski vzorec, ki zahteva eksplicitno posredovanje odvisnosti med objekti.
Lahko torej rečemo, da je DI specifična oblika IoC. Vendar niso vse oblike IoC primerne z vidika čistosti kode. Na primer, med antivzorci so tehnike, ki delujejo z globalnim stanjem ali tako imenovani Service Locator.
Kaj je Service Locator?
Gre za alternativo Dependency Injection. Deluje tako, da ustvari centralno shrambo, kjer so registrirane vse razpoložljive storitve ali odvisnosti. Ko objekt potrebuje odvisnost, zanjo prosi Service Locator.
V primerjavi z Dependency Injection pa izgublja na transparentnosti: odvisnosti niso objektom posredovane neposredno in niso tako enostavno prepoznavne, kar zahteva pregled kode, da bi bile vse povezave odkrite in razumljene. Testiranje je prav tako bolj zapleteno, ker ne moremo preprosto posredovati mock objektov testiranim objektom, ampak moramo iti prek Service Locatorja. Poleg tega Service Locator krši načrtovanje kode, saj morajo posamezni objekti vedeti za njegov obstoj, kar se razlikuje od Dependency Injection, kjer objekti nimajo vedenja o DI vsebniku.
Kdaj je bolje DI ne uporabiti?
Niso znane nobene težave, povezane z uporabo načrtovalskega vzorca Dependency Injection. Nasprotno, pridobivanje odvisnosti iz globalno dostopnih mest vodi k celi vrsti zapletov, enako velja za uporabo Service Locatorja. Zato je primerno uporabljati DI vedno. To ni dogmatski pristop, ampak preprosto ni bila najdena boljša alternativa.
Kljub temu obstajajo določene situacije, ko si objektov ne posredujemo in jih pridobimo iz globalnega prostora. Na primer pri razhroščevanju kode, ko morate na določeni točki programa izpisati vrednost spremenljivke, izmeriti trajanje določenega dela programa ali zabeležiti sporočilo. V takih primerih, ko gre za začasna dejanja, ki bodo kasneje odstranjena iz kode, je legitimno uporabiti globalno dostopen dumper, štoparico ali logger. Ti orodji namreč ne spadajo k načrtovanju kode.
Ima uporaba DI svoje slabe strani?
Ali uporaba Dependency Injection prinaša kakšne slabosti, kot na primer povečano zahtevnost pisanja kode ali poslabšano zmogljivost? Kaj izgubimo, ko začnemo pisati kodo v skladu z DI?
DI nima vpliva na zmogljivost ali pomnilniške zahteve aplikacije. Določeno vlogo lahko igra zmogljivost DI Containerja, vendar v primeru Nette DI je vsebnik preveden v čisti PHP, tako da je njegova režija med izvajanjem aplikacije v bistvu nična.
Pri pisanju kode je včasih treba ustvarjati konstruktorje, ki sprejemajo odvisnosti. Prej je to lahko bilo dolgotrajno, vendar je zahvaljujoč sodobnim IDE in constructor property promotion zdaj vprašanje nekaj sekund. Tovarne lahko enostavno generiramo z Nette DI in vtičnikom za PhpStorm s klikom miške. Po drugi strani odpade potreba po pisanju singletonov in statičnih dostopnih točk.
Lahko ugotovimo, da pravilno načrtovana aplikacija, ki uporablja DI, v primerjavi z aplikacijo, ki uporablja singletone, ni niti krajša niti daljša. Deli kode, ki delajo z odvisnostmi, so le izvzeti iz posameznih razredov in premaknjeni na nova mesta, torej v DI vsebnik in tovarne.
Kako prenoviti staro aplikacijo na DI?
Prehod s stare aplikacije na Dependency Injection je lahko zahteven proces, zlasti pri velikih in kompleksnih aplikacijah. Pomembno je, da k temu procesu pristopimo sistematično.
- Pri prehodu na Dependency Injection je pomembno, da vsi člani ekipe razumejo načela in postopke, ki se uporabljajo.
- Najprej izvedite analizo obstoječe aplikacije in identificirajte ključne komponente ter njihove odvisnosti. Ustvarite načrt, kateri deli bodo refaktorirani in v kakšnem vrstnem redu.
- Implementirajte DI vsebnik ali še bolje uporabite obstoječo knjižnico, na primer Nette DI.
- Postopoma refaktorirajte posamezne dele aplikacije, da bodo uporabljali Dependency Injection. To lahko vključuje prilagoditve konstruktorjev ali metod tako, da sprejemajo odvisnosti kot parametre.
- Prilagodite mesta v kodi, kjer se ustvarjajo objekti z odvisnostmi, da bodo namesto tega odvisnosti injicirane z vsebnikom. To lahko vključuje uporabo tovarn.
Ne pozabite, da je prehod na Dependency Injection naložba v kakovost kode in dolgoročno vzdržljivost aplikacije. Čeprav je lahko zahtevno izvesti te spremembe, bi moral biti rezultat čistejša, bolj modularna in enostavno testirana koda, ki je pripravljena za prihodnje razširitve in vzdrževanje.
Zakaj se daje prednost kompoziciji pred dedovanjem?
Primerneje je uporabljati kompozicijo namesto dedovanja, ker služi za ponovno uporabo kode, ne da bi se morali ukvarjati s posledicami sprememb. Zagotavlja torej ohlapnejšo povezavo, pri kateri se nam ni treba bati, da bo sprememba neke kode povzročila potrebo po spremembi druge odvisne kode. Tipičen primer je situacija, označena kot constructor hell.
Ali je mogoče uporabiti Nette DI Container zunaj Nette?
Vsekakor. Nette DI Container je del Nette, vendar je zasnovan kot samostojna knjižnica, ki jo je mogoče uporabiti neodvisno od drugih delov ogrodja. Zadostuje jo namestiti z Composerjem, ustvariti konfiguracijsko datoteko z definicijo vaših storitev in nato z nekaj vrsticami PHP kode ustvariti DI vsebnik. In takoj lahko začnete izkoriščati prednosti Dependency Injection v svojih projektih.
Kako izgleda konkretna uporaba, vključno s kodami, opisuje poglavje Nette DI Container.
Zakaj je konfiguracija v NEON datotekah?
NEON je preprost in lahko berljiv konfiguracijski jezik, ki je bil razvit v okviru Nette za nastavitev aplikacij, storitev in njihovih odvisnosti. V primerjavi z JSONom ali YAMLom ponuja za ta namen veliko bolj intuitivne in fleksibilne možnosti. V NEONu je mogoče naravno opisati povezave, ki jih v Symfony & YAMLu ne bi bilo mogoče zapisati bodisi sploh, bodisi le prek zapletenega opisa.
Ali razčlenjevanje NEON datotek upočasnjuje aplikacijo?
Čeprav se datoteke NEON razčlenjujejo zelo hitro, ta vidik sploh ni pomemben. Razlog je, da se razčlenjevanje datotek zgodi samo enkrat ob prvem zagonu aplikacije. Nato se generira koda DI vsebnika, shrani se na disk in se zažene ob vsakem naslednjem zahtevku, ne da bi bilo treba izvajati nadaljnje razčlenjevanje.
Tako to deluje v produkcijskem okolju. Med razvojem se NEON datoteke razčlenjujejo vsakič, ko pride do spremembe njihove vsebine, da ima razvijalec vedno aktualen DI vsebnik. Samo razčlenjevanje je, kot je bilo rečeno, vprašanje trenutka.
Kako iz svojega razreda dostopam do parametrov v konfiguracijski datoteki?
Imejmo v mislih Pravilo št. 1: naj ti posredujejo. Če razred zahteva informacije iz konfiguracijske datoteke, nam ni treba razmišljati, kako do teh informacij priti, namesto tega jih preprosto zahtevamo – na primer prek konstruktorja razreda. In posredovanje izvedemo v konfiguracijski datoteki.
V tej predstavitvi je %myParameter%
nadomestni znak za vrednost parametra myParameter
, ki se
posreduje v konstruktor razreda MyClass
:
# config.neon
parameters:
myParameter: Some value
services:
- MyClass(%myParameter%)
Če želite posredovati več parametrov ali izkoristiti autowiring, je primerno parametre zapakirati v objekt.
Ali Nette podpira PSR-11: Container interface?
Nette DI Container ne podpira PSR-11 neposredno. Vendar, če potrebujete interoperabilnost med Nette DI Containerjem in knjižnicami ali ogrodji, ki pričakujejo PSR-11 Container Interface, lahko ustvarite preprost adapter, ki bo služil kot most med Nette DI Containerjem in PSR-11.