všetky vzory

Flyweight

Zdieľa nemennú časť stavu medzi mnohými objektmi a šetrí tak pamäť.

class Glyf {  constructor(pismeno, font) {    this.pismeno = pismeno;    this.font = font;  }   vykresli(x, y) {    // nakreslí sa na zadanú pozíciu  }} class GlyfyTovaren {  static #zdielane = new Map();   static pre(pismeno) {    if (!GlyfyTovaren.#zdielane.has(pismeno)) {      GlyfyTovaren.#zdielane.set(pismeno, new Glyf(pismeno, 'serif'));    }    return GlyfyTovaren.#zdielane.get(pismeno);  }} class Vyskyt {  constructor(pismeno, x, y) {    this.glyf = GlyfyTovaren.pre(pismeno);    this.x = x;    this.y = y;  }   vykresli() {    this.glyf.vykresli(this.x, this.y);  }} const a1 = new Vyskyt('a', 10, 4);const a2 = new Vyskyt('a', 24, 4);const b1 = new Vyskyt('b', 38, 4); a1.glyf === a2.glyf;   // true — spoločná časť je jednaa1.x === a2.x;         // false — vlastnú si drží každý

Celý priebeh v texte (12 krokov)
  1. Glyf je nemenná časť písmena: jeho tvar a font. Nezávisí od toho, kde v texte stojí — a práve preto sa dá zdieľať.
  2. Prvý výskyt písmena "a" si vypýta glyf z registra.
  3. Pre "a" ešte nič nie je, takže glyf práve teraz vzniká — jediný raz za celý text.
  4. Von neputuje kópia, ale referencia na zdieľaný glyf.
  5. A vedľa nej si výskyt drží svoju vlastnú časť: pozíciu v texte. Tú nezdieľa s nikým.
  6. Druhý výskyt toho istého písmena si tiež vypýta glyf.
  7. Register nevyrobí nič nové. Vráti referenciu na ten istý glyf, aký dostal prvý výskyt — dve lanká, jedna gulička.
  8. Vlastnú pozíciu má ale inú. Zdieľa sa nemenná časť, nie celý objekt.
  9. Tretí výskyt je iné písmeno. Pýta si glyf pre "b".
  10. Preň v registri nič nie je, tak vzniká druhý zdieľaný glyf. Koľko ich bude, určuje počet rôznych písmen — nie počet výskytov.
  11. Aj tento výskyt si drží svoju pozíciu.
  12. Tri výskyty, ale iba dva glyfy. Vlastnú časť má každý svoju, spoločnú si podávajú — a keby ich boli tisíce, glyfy by stále boli dva. To je celá úspora.

Kedy použiť

  • Objektov je veľa a väčšina z nich nesie to isté. Tisíce znakov na stránke sa líšia pozíciou, nie tvarom písmena — a tvar stačí jeden na každé písmeno.
  • Stav sa dá rozdeliť na nemennú a meniteľnú časť. Nemenná sa dá zdieľať bez rizika, meniteľná zostáva u toho, komu patrí.
  • Pamäť je úzke hrdlo, nie čas. Vzor vymieňa jedno za druhé — ušetrí miesto a zaplatí za to vyhľadaním v registri a nepriamosťou.
  • Rovnaké objekty sa vytvárajú znova a znova. Register ich vydá namiesto toho, aby ich program tvoril zakaždým odznova.

Pasce

  • Zdieľaná časť musí byť nemenná. Stačí jeden setter a zmena u jedného držiteľa sa prejaví u všetkých ostatných — chyba, ktorá sa hľadá najhoršie zo všetkých.
  • Zamieňa sa so Singletonom. Singleton hovorí „na svete práve jedna instancia"; tu je instancií toľko, koľko je rôznych nemenných hodnôt, a každá má mnoho držiteľov.
  • Zamieňa sa s Multitonom. Register podľa kľúča je len časť vzoru. Flyweight je hlavne o rozdelení stavu na zdieľaný a vlastný — bez toho rozdelenia sa nešetrí nič.
  • Vonkajší stav musí niekto niesť. Keď sa presunie k volajúcemu, jeho kód sa skomplikuje presne o to, o čo sa zjednodušil zdieľaný objekt.
  • Register drží objekty navždy. Zdieľané kusy sa spravidla neuvoľňujú, takže úspora pamäte sa pri veľa rôznych hodnotách zmení na trvalý sklad.
  • Nepriamosť stojí čas. Každé použitie znamená vyhľadanie a skok inam — pri malom počte objektov je réžia väčšia než ušetrené miesto.
  • Zdieľanie sa prezradí porovnaním. Dva výskyty držia tú istú instanciu, takže porovnanie na identitu odpovie „to isté" tam, kde volajúci čakal „dve rôzne veci".