všetky vzory

Decorator

Obaľuje objekt vrstvami, ktoré mu pridávajú chovanie bez dedenia.

class Beverage {  description() { throw new Error('abstraktná metóda'); }} class Espresso extends Beverage {  description() { return 'espresso'; }} class CondimentDecorator extends Beverage {  constructor(beverage) {    super();    this.beverage = beverage;  }} class Milk extends CondimentDecorator {  description() { return this.beverage.description() + ', mlieko'; }} class Sugar extends CondimentDecorator {  description() { return this.beverage.description() + ', cukor'; }} // Tri triedy, štyri nápoje — stačí ich poskladať inak.new Espresso().description();                       // 'espresso'new Sugar(new Espresso()).description();            // 'espresso, cukor'new Milk(new Espresso()).description();             // 'espresso, mlieko'new Sugar(new Milk(new Espresso())).description();  // 'espresso, mlieko, cukor'

Celý priebeh v texte (14 krokov)
  1. Beverage je abstraktný. Espresso aj obe prísady sú navonok nápoj, a preto sa prísada dá pridať na čokoľvek — aj na to, čo už raz obalené bolo.
  2. Prvá objednávka: čisté espresso. CoffeeShop sa spýta priamo espressa — žiadna vrstva medzi nimi nie je, tak volanie obe prísady obchádza spodkom.
  3. Espresso vyrobí nápoj a vráti ho. Odtiaľto už neletí volanie, ale hotový objekt — a cestou von sa k nemu nemá čo pridať.
  4. Druhá objednávka: espresso s mliekom. Volanie ide ku mlieku a mlieko sa spýta espressa. Ďalej už nemá koho.
  5. Espresso vyrobí nápoj a pošle ho von — mlieku, ktoré si o neho pýtalo.
  6. Mlieko ho obalí — pridá mu vrstvu a drží si naň referenciu — a takto obalený ho pošle na výdaj.
  7. Tretia objednávka: espresso s cukrom. Volanie ide ku cukru a cukor sa spýta espressa. Mlieko o tomto nápoji nevie nič — volanie k nemu ani nezavíta.
  8. Nápoj sa vracia ku cukru. Mlieko obchádza rovnako, ako ho obišlo volanie.
  9. Cukor pridá svoju vrstvu a nápoj ide na výdaj. Iná prísada, iná farba — na výdaji je potom vidno, čo v ktorom nápoji je.
  10. Štvrtá objednávka: espresso s mliekom aj cukrom. Volanie sa prepadáva vrstvu po vrstve: CoffeeShop sa spýta cukru, cukor mlieka a mlieko espressa.
  11. Espresso vyrobí nápoj a pošle ho von. Vracia sa presne tou cestou, akou prišlo volanie.
  12. Mlieko pridá vrstvu a posunie nápoj ďalej ku cukru. Cukor nevie, či dostane espresso alebo espresso s mliekom — vie len, že je to nápoj.
  13. Cukor pridá druhú vrstvu a hotový nápoj ide na výdaj. Dve vrstvy na jednom espresse, každá pridala svoje.
  14. Štyri rôzne nápoje z tých istých troch tried. Vrstvy, ktoré nápoj nabral, sú presne tie, cez ktoré prešlo volanie — a dajú sa poskladať inak za behu. Dedením by na každú kombináciu musela vzniknúť trieda: pri desiatich prísadách tisíc tried.

Kedy použiť

  • Chceš vlastnosť pridať jednej inštancii, nie celej triede. Espresso s mliekom nemá byť nový druh nápoja.
  • Kombinácií je viac, než sa oplatí popísať triedami. Tri prísady sú osem kombinácií, čiže osem podtried — alebo tri dekorátory, ktoré si poskladáš.
  • Prísadu treba pridať či odobrať za behu, podľa objednávky alebo konfigurácie. Logovanie, cache, kompresia, retry — to isté ako mlieko a cukor.
  • Trieda, ktorú obaľuješ, je cudzia alebo final a nemôžeš do nej zasahovať.

Pasce

  • Poradie vrstiev môže meniť výsledok. Espresso, mlieko, cukor a espresso, cukor, mlieko dajú iný popis — a z volania new to nie je vidno.
  • Nič nezabráni pridať tú istú vrstvu dvakrát. Dvojité mlieko je platný objekt, aj keď si ho nechcel.
  • Obalený nápoj už nie je pôvodný objekt. instanceof Espresso na hotovú objednávku neprejde a k jeho vlastným metódam sa cez obal nedostaneš.
  • Vrstva nevidí celok, vie len o tej pod sebou. Zľava za tri prísady alebo pravidlo „mlieko a smotana spolu nie" sa v jednotlivých vrstvách vyhodnotiť nedá.
  • V stacktrace vidíš päť skoro rovnakých rámcov description(). Čím viac vrstiev, tým ťažšie sa hľadá, ktorá pokazila výsledok.
  • Zamieňa sa s Proxy. Obe držia obalený objekt, ale dekorátor pridáva chovanie a skladá sa do vrstiev, proxy prístup riadi alebo odkladá a býva jeden.