všetky vzory

Composite

Umožní pracovať so stromom objektov rovnako ako s jediným objektom.

class Polozka {  velkost() { throw new Error('abstraktná metóda'); }} class Subor extends Polozka {  constructor(bajtov) {    super();    this.bajtov = bajtov;  }   velkost() {    return this.bajtov;  }} class Priecinok extends Polozka {  deti = [];   pridaj(polozka) {    this.deti.push(polozka);  }   velkost() {    let spolu = 0;    for (const dieta of this.deti) {      spolu += dieta.velkost();    }    return spolu;  }} const album = new Priecinok();album.pridaj(new Subor(900)); const koren = new Priecinok();koren.pridaj(new Subor(120));koren.pridaj(album); koren.velkost();   // 1020 — klient sa nepýtal, čo je vnútri

Celý priebeh v texte (11 krokov)
  1. Polozka je abstraktná a vie jediné: povedať svoju veľkosť. Dedia ju obe strany stromu — súbor aj priečinok. Práve preto sa dá so stromom pracovať ako s jedným objektom.
  2. Koren je priečinok, takže drží deti — dve. Jedno je súbor, druhé je zase priečinok, a je to možné práve preto, že oba sú Polozka.
  3. A Album drží svoje vlastné dieťa. Strom je tým postavený a má tri poschodia — lanká sú väzby rodič a dieťa.
  4. Klient zavolá velkost() na koreni. Je to jedno volanie na jednom objekte — o tom, čo je vnútri, nevie a ani nechce vedieť.
  5. Koren sa nepýta, čo v ňom je. Pošle to isté volanie prvému dieťaťu.
  6. a.txt je list. Nemá deti, takže volanie nikam ďalej neposiela — jednoducho odpovie.
  7. Druhé dieťa dostane presne to isté volanie. Koren nerobí rozdiel medzi prvým a druhým, oba sú preň len Polozka.
  8. Lenže Album je priečinok — a spraví presne to, čo pred chvíľou koreň: pošle to isté volanie ďalej svojmu dieťaťu. Toto je rekurzia a je to celý vzor.
  9. b.jpg je zase list, takže tu sa vetvenie končí.
  10. Album spočíta odpovede svojich detí a vráti výsledok koreňu, ako keby bol obyčajný súbor. Koreň spočíta to svoje a vráti klientovi jedno číslo.
  11. Jedno volanie na jednom objekte prešlo celý strom. A v žiadnom kroku sa nikto nespýtal „si list alebo priečinok?" — to je presne tá otázka, ktorú vzor odstraňuje.

Kedy použiť

  • Dáta tvoria strom a klient s nimi má pracovať rovnako na každej úrovni. Priečinok aj súbor odpovedia na tú istú otázku a volajúci nemusí vedieť, ktorý z nich drží.
  • Kód je posiaty otázkou „je to jeden alebo skupina?". Vzor tú otázku odstráni tým, že skupina je tiež jeden — má rovnaké rozhranie ako jej prvky.
  • Hĺbka stromu nie je známa dopredu. Rekurzia sa postará o ľubovoľné vnorenie bez toho, aby klient písal jediný cyklus.
  • Operácia sa má dať spustiť nad ľubovoľnou vetvou. Ten istý kód spracuje celý strom aj jediný list, lebo medzi nimi nerobí rozdiel.

Pasce

  • Spoločné rozhranie klame na polovici prípadov. Keď je v ňom pridaj() a odober(), list ich musí mať tiež — a nemá čo s nimi robiť, takže buď mlčí, alebo hádže výnimku.
  • Bezpečnosť a jednotnosť sa nedajú mať naraz. Buď je rozhranie jednotné a list má metódy, ktoré nedávajú zmysel, alebo je bezpečné a klient sa musí pýtať na typ — teda presne to, čo mal vzor odstrániť.
  • Cyklus v strome znamená nekonečnú rekurziu. Nič vo vzore nebráni tomu, aby sa priečinok stal svojím vlastným potomkom, a prejdenie stromu potom nikdy neskončí.
  • Operácia nad veľkým stromom je drahá a nevidno to. Jedno volanie vyzerá ako jedno volanie, no môže prejsť státisíce uzlov — cena je skrytá presne tak dobre ako štruktúra.
  • Zamieňa sa s Decoratorom. Dekorátor obaľuje práve jeden objekt a pridáva mu chovanie; kompozit ich drží viac a chovanie len skladá z ich odpovedí. Rovnaké rozhranie majú oba, úmysel majú opačný.
  • Poradie detí sa stane skrytým pravidlom. Kým operácia len sčítava, nezáleží naň — pri prvej operácii, ktorej záleží, sa ukáže, že ho nikto nikde nezaručil.
  • Rodič a dieťa sa začnú odkazovať navzájom. Spätný odkaz na rodiča sa zíde, ale vyrobí cyklus vo vlastníctve a upratovanie stromu prestane byť triviálne.