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ť

  • Vlastnosť patrí jednej inštancii, nie celej triede — espresso s mliekom nie je nový druh nápoja.
  • Tri prísady sú osem podtried, alebo tri dekorátory na poskladanie.
  • Prísada pribúda a ubúda za behu — logovanie, cache, kompresia, retry ako mlieko a cukor.
  • Obaľovaná trieda je cudzia alebo final a zasiahnuť sa do nej nedá.

Pasce

  • Poradie vrstiev môže meniť výsledok a z volania new to nie je vidno.
  • Nič nebráni pridať tú istú vrstvu dvakrát; dvojité mlieko je platný objekt.
  • Obalený nápoj už nie je pôvodný objekt: instanceof Espresso neprejde a jeho metódy sú za obalom.
  • Vrstva vie len o tej pod sebou, takže pravidlo „mlieko a smotana spolu nie" sa v nej nevyhodnotí.
  • V stacktrace je päť skoro rovnakých rámcov description() a nevidno, ktorý pokazil výsledok.
  • Zamieňa sa s Proxy: dekorátor pridáva chovanie vo vrstvách, proxy riadi prístup a býva jeden.