všetky vzory

RAII

Naviaže zdroj na životnosť objektu — pri jeho zániku sa zdroj uvoľní sám.

class SuborovyStraz {  constructor(cesta) {    // Získanie zdroja je súčasťou vzniku objektu.    this.subor = Subor.otvor(cesta);  }   // Zánik objektu zdroj uvoľní. Nie je to krok programu, je to dôsledok.  [Symbol.dispose]() {    this.subor.zatvor();  }} function spracuj(cesta) {  using straz = new SuborovyStraz(cesta);   zapis(straz.subor);  overPrava();          // odtiaľto môže vyletieť chyba   // Koniec bloku. Nikde nie je zatvor() — a súbor je aj tak zavretý.}

Celý priebeh v texte (12 krokov)
  1. SuborovyStraz nerobí nič iné, než že drží zdroj. Získa ho pri svojom vzniku a pustí pri svojom zániku — medzi tým nemá žiadnu úlohu.
  2. Funkcia si stráž vytvorí ako lokálnu premennú. Nikto jej ju nepodal a nikam neputuje — vzniká priamo v bloku a jeho život bude aj jej životom.
  3. Vznik stráže je zároveň otvorenie súboru. Konštruktor to spraví sám — nie je to samostatný krok, na ktorý sa dá zabudnúť.
  4. Súbor je otvorený a od tejto chvíle ho stráž drží. Kto má stráž, má zdroj.
  5. Funkcia si robí svoju prácu. O zatváraní v nej nie je ani zmienka.
  6. Blok sa končí. Lokálna premenná zaniká a jej zánik volá zatvor().
  7. A tu je vzor celý: zanikla stráž a s ňou v tom istom okamihu zdroj. V kóde funkcie nie je ani jedno zatvor() — uvoľnenie nie je krok, ktorý by niekto napísal.
  8. Druhý priebeh. Začiatok je rovnaký — stráž vzniká a súbor sa otvára.
  9. Lenže uprostred práce vyletí chyba. Blok sa opúšťa hneď a ani jeden riadok za tým miestom sa nevykoná — keby tam zatvor() bolo napísané, práve teraz by sa preskočilo.
  10. Stráž ale zaniká aj tak. Opustenie bloku je opustenie bloku, či už riadnym koncom alebo chybou.
  11. Súbor je zavretý rovnako spoľahlivo ako pri prvom priebehu.
  12. Dva priebehy, jeden koniec: uvoľnenie zdroja nie je krok programu, ale dôsledok zániku toho, kto ho vlastnil. Práve preto sa nedá zabudnúť, obísť ani preskočiť chybou.

Kedy použiť

  • Zdroj sa musí uvoľniť vždy, aj keď z bloku vyletí chyba. Uvoľnenie viazané na zánik objektu nemá ako vynechať — nie je to riadok, ktorý sa dá preskočiť.
  • Vlastníctvo zdroja má byť čitateľné z typu. Kto drží stráž, drží zdroj; kto ju nemá, nemá čo uvoľňovať a nemusí o tom nič vedieť.
  • Zdrojov je v jednom bloku viac a musia sa uvoľniť v opačnom poradí, než vznikli. Viazanie na životnosť to spraví samo a správne poradie nie je na programátorovi.
  • Párové operácie sa dajú zabudnúť. Otvor a zavri, zamkni a odomkni, zaber a vráť — druhá polovica páru patrí do zániku objektu, nie do disciplíny toho, kto ho používa.

Pasce

  • Vzor stojí a padá na tom, že zánik nastane v presne určenej chvíli. Tam, kde objekty upratuje garbage collector, sa zdroj uvoľní neskôr alebo nikdy — a vzor prestáva byť vzorom, aj keď kód vyzerá rovnako.
  • Stráž prežije blok, ak si na ňu niekto nechá odkaz. Uloženie do poľa alebo návrat z funkcie predĺžia jej život a zdroj sa neuvoľní tam, kde to čakáte.
  • Skopírovaná stráž uvoľní zdroj dvakrát. Dva objekty presvedčené, že zdroj vlastnia, ho pri zániku obidva zatvoria — a druhé zatvorenie je chyba.
  • Chyba pri uvoľňovaní nemá kam ísť. Zánik objektu je zlé miesto na výnimku: prebieha často práve vtedy, keď sa už jedna chyba spracúva.
  • Stráž, ktorá robí viac než drží zdroj, prestane byť čitateľná. Jej jediná úloha je pár získaj a uvoľni — akonáhle k tomu pribudne logika, nikto nevie, čo sa pri zániku stane.
  • Zdroj sa uvoľní aj vtedy, keď to nechcete. Predčasný koniec bloku zavrie spojenie, ktoré ste chceli podržať — a vzor to spraví ticho a spoľahlivo.
  • Zamieňa sa s Object Poolom. Pool objekt požičia a berie ho späť, stráž ho vlastní a pri zániku ho zruší. Prvý rieši cenu vzniku, druhý istotu uvoľnenia.