všetky vzory

Visitor

Pridá operáciu nad štruktúrou objektov bez zásahu do ich tried.

class Prvok {  prijmi(navstevnik) { throw new Error('abstraktná metóda'); }} class Kruh extends Prvok {  constructor(r) {    super();    this.r = r;  }   // Kruh operáciu nevykoná. Odovzdá riadenie a podá seba.  prijmi(navstevnik) {    navstevnik.navstivKruh(this);  }} class Stvorec extends Prvok {  constructor(a) {    super();    this.a = a;  }   prijmi(navstevnik) {    navstevnik.navstivStvorec(this);  }} class Navstevnik {  navstivKruh(kruh) { throw new Error('abstraktná metóda'); }  navstivStvorec(stvorec) { throw new Error('abstraktná metóda'); }} class PlochaVypocet extends Navstevnik {  navstivKruh(kruh) {    return Math.PI * kruh.r * kruh.r;  }   navstivStvorec(stvorec) {    return stvorec.a * stvorec.a;  }} const plocha = new PlochaVypocet();kruh.prijmi(plocha);stvorec.prijmi(plocha);

Celý priebeh v texte (8 krokov)
  1. Prvok je abstraktný a vie jedinú vec: prijať návštevníka. Kruh aj štvorec ho dedia — a to je všetko, čo o operáciách vedia.
  2. Vpravo je druhá hierarchia: operácie. PlochaVypocet je jedna z nich a nesie celý výpočet — ten nie je v žiadnom z tvarov.
  3. Klient povie kruhu: prijmi tohto návštevníka.
  4. A tu je vzor: kruh nevypočíta nič. Odrazí volanie späť von — zavolá návštevníka a podá mu seba. Prvé volanie určilo, ktorý tvar; druhé, ktorá operácia. To je dvojité odoslanie.
  5. To isté so štvorcom. Klient volá rovnako a o výpočte nevie nič.
  6. Aj štvorec len odovzdá riadenie — ale inou metódou, lebo je iný typ. Návštevník tak vie, s čím pracuje, bez toho, aby sa na to musel pýtať.
  7. Celý výpočet plochy je na jednom mieste, v jednej triede — nie rozdrobený po tvaroch. A nová operácia znamená nového návštevníka: tvary sa nezmenia ani o písmeno.
  8. Cena je opačná strana tej istej mince: pridať nový tvar znamená zasiahnuť do každého návštevníka. Vzor uľahčuje pridávanie operácií a sťažuje pridávanie typov — oplatí sa tam, kde je skupina tried ustálená.

Kedy použiť

  • Nad ustálenou skupinou tried treba pribúdajúce operácie. Každá nová je jeden návštevník a do samotných tried sa nesiaha.
  • Operácia patrí inam než dáta. Výpočet plochy, export, kontrola — sú to veci o tvaroch, nie vlastnosti tvarov.
  • Súvisiaci kód sa má držať pohromade. Celý výpočet je v jednej triede namiesto toho, aby bol rozdrobený po všetkých prvkoch.
  • Cudzie triedy sa meniť nedajú, ale musia mať jednu vec navyše — a tú jednu vec sú ochotné pustiť dnu cez prijmi().

Pasce

  • Pridať typ je drahé, pridať operáciu lacné. Nový tvar znamená zásah do každého návštevníka — vzor je výhodný len vtedy, keď je skupina tried ustálená a operácií pribúda.
  • Dvojité odoslanie sa ťažko číta. Volanie ide do prvku a odtiaľ späť do návštevníka; kto to vidí prvýkrát, nevie, prečo to nejde priamo.
  • Návštevník potrebuje vidieť do prvkov. Aby operáciu vykonal, musia mu vydať svoj stav — a zapuzdrenie tým trpí.
  • Prvky musia vedieť o návštevníkovi. Metóda prijmi() je v nich kvôli operáciám, ktoré s nimi nesúvisia; nezávislosť teda nie je úplná.
  • Zamieňa sa s Iteratorom. Iterátor rieši, ako prejsť štruktúru; návštevník, čo sa má s každým prvkom stať. Často idú spolu, ale odpovedajú na iné otázky.
  • Návštevník so stavom sa nedá použiť dvakrát. Keď si medzi prvkami niečo zbiera, po prvom prechode je použitý — a druhý dá zlý výsledok.
  • Metód pribúda súčinom. Pri piatich tvaroch má každý návštevník päť metód a väčšina z nich vyzerá skoro rovnako.