všetky vzory

Dependency Injection

Podá objektu jeho závislosti zvonku namiesto toho, aby si ich zháňal sám.

class Zaznamnik {  zapis(sprava) { throw new Error('abstraktná metóda'); }} class KonzolovyZaznamnik extends Zaznamnik {  zapis(sprava) { console.log(sprava); }} class SuborovyZaznamnik extends Zaznamnik {  zapis(sprava) { this.subor.pridaj(sprava); }} // Takto nie: závislosť vzniká vnútri a zvonku sa nedá vymeniť.class SluzbaZle {  constructor() {    this.zaznamnik = new KonzolovyZaznamnik();  }} // Takto áno: čo služba použije, to dostane zvonku.class Sluzba {  constructor(zaznamnik) {    this.zaznamnik = zaznamnik;  }  prijmi(objednavka) {    this.zaznamnik.zapis('prijatá ' + objednavka.id);  }} // Zostavovač je jediné miesto, kde sa volí konkrétna implementácia.const doKonzoly = new Sluzba(new KonzolovyZaznamnik());doKonzoly.prijmi(objednavka); const doSuboru = new Sluzba(new SuborovyZaznamnik());doSuboru.prijmi(objednavka);   // ten istý kód služby, iný výstup

Celý priebeh v texte (13 krokov)
  1. Zaznamnik je abstraktný. Hovorí len to, že sa doň dá zapísať správa — nič o tom, kam. Obe implementácie ho dedia a služba nebude poznať ani jednu z nich.
  2. Najprv tak, ako sa to píše bez vzoru. Sluzba si záznamník vyrobí sama vo vnútri — objekt vzniká priamo v nej a po scéne k nej neviedla žiadna dráha.
  3. Funguje to a presne v tom je pasca. Zvonku sa ten objekt nedá vymeniť — kto chce službu s iným záznamníkom, musí prepísať jej konštruktor. A v teste dostane skutočnú konzolu, či chce alebo nie.
  4. Tak to skúsme naopak: nech si závislosť nezháňa sama.
  5. Zostavovač vyrobí konzolový záznamník. On jediný pozná konkrétnu triedu — a je to jediné miesto v aplikácii, kde sa tá voľba robí.
  6. A teraz to podstatné: hotový objekt podá službe. Sluzba oň nežiadala, nič nevolala — dostala ho. Po tejto dráhe nikdy neletí volanie, len objekt.
  7. Sluzba prijme objednávku a zapíše o nej riadok. Volá metódu zo Zaznamnika a netuší, ktorá implementácia jej prišla.
  8. Zapísalo sa do konzoly. Nie preto, že by to Sluzba chcela — preto, že jej to zostavovač podal.
  9. Druhá zostava. Rovnaká aplikácia chce zapisovať do súboru, takže zostavovač vyrobí súborový záznamník.
  10. Podá ho do tej istej komory. Rovnaký tvar, lebo je to ten istý typ — iná farba, lebo je to iná implementácia.
  11. Sluzba prijme objednávku a zapíše o nej riadok — ten istý riadok kódu ako pred chvíľou.
  12. Tentoraz to skončilo v súbore. Volanie bolo rovnaké, výsledok iný.
  13. A to je celý vzor: medzi oboma kolami sa v triede Sluzba nezmenilo ani písmeno. Nezmenila sa preto, že si závislosť nikdy nevyrábala — rozhodnutie, ktorá to bude, nikdy nebolo v nej.

Kedy použiť

  • Tú istú triedu treba spustiť s inou spoluprácou. V teste s falošným záznamníkom, v prevádzke so skutočným — bez toho, aby si trieda o tom rozdiele vedela.
  • Voľba konkrétnej implementácie má byť na jednom mieste. Keď si ju každá trieda robí sama, zmena znamená obísť celú aplikáciu a nikto nevie, či ste našli všetky.
  • Trieda má robiť svoju prácu, nie zháňať spolupracovníkov. Vytvorenie závislosti je druhá zodpovednosť a spravidla tá, ktorá do triedy patrí najmenej.
  • Závislosť je drahá alebo má vlastný životný cyklus — spojenie do databázy, pool, klient externej služby. Kto ju používa, nemusí byť ten, kto ju vlastní a zatvára.
  • Závislosti triedy majú byť vidieť na prvý pohľad. V hlavičke konštruktora sú vymenované; poschovávané v tele metód sa o nich dozviete až za behu.

Pasce

  • Zamieňa sa so Service Locatorom. Ten vyzerá podobne, ale objekt si závislosť ťahá z registra sám — čiže si ju stále zháňa, len o poschodie nižšie. Vzor je práve o opaku: dostane ju a nemá sa koho pýtať.
  • Kontajner sa vydáva za vzor. Vzor je odovzdanie závislosti zvonku a funguje úplne rovnako, keď ju podáte ručne. Kontajner je nástroj na to, aby ste ju nepodávali cez desať vrstiev — nie samotný vzor.
  • Injektovanie neuberie ani jednu závislosť. Konštruktor s ôsmimi parametrami je stále zle navrhnutá trieda; vzor to len prestane skrývať. Keď vás počet parametrov zabolí, je to nález, nie chyba vzoru.
  • Podaná závislosť ešte nie je vymeniteľná. Keď klient volá metódy, ktoré má len jedna implementácia, väzba zostala — presunula sa z konštruktora do tela.
  • Chyba sa presunie z vytvorenia na použitie. Zle zostavená služba vyzerá v poriadku dovtedy, kým niekto nezavolá metódu, ktorá chýbajúcu závislosť naozaj potrebuje.
  • Kruh v závislostiach nemá kde začať. Keď A potrebuje B a B potrebuje A, zostavovač nevie, čo vyrobiť ako prvé — a je to signál o návrhu, nie o zostavovaní.
  • Zostavovač zhustne. Všetky rozhodnutia o implementáciách sú na jednom mieste, a to miesto rastie s aplikáciou. Je to výhodná výmena, ale nie výmena za nič.