všetky vzory

Servant

Vyčlení spoločné chovanie do objektu, ktorý ho vykoná pre viac tried.

class Posunutelne {  poloha() { throw new Error('abstraktná metóda'); }  nastavPolohu(x, y) { throw new Error('abstraktná metóda'); }} class Kruh extends Posunutelne {  poloha() {    return this.stred;  }   nastavPolohu(x, y) {    this.stred = { x, y };  }} class Obdlznik extends Posunutelne {  poloha() {    return this.lavyHorny;  }   nastavPolohu(x, y) {    this.lavyHorny = { x, y };  }} // Sluha. Posúvanie nie je ani v kruhu, ani v obdĺžniku — je tu.class Posuvac {  posun(tvar, dx, dy) {    const p = tvar.poloha();    tvar.nastavPolohu(p.x + dx, p.y + dy);  }} const posuvac = new Posuvac();posuvac.posun(kruh, 10, 0);posuvac.posun(obdlznik, 10, 0);

Celý priebeh v texte (9 krokov)
  1. Posunutelne je abstraktné: vie povedať svoju polohu a nastaviť novú. Kruh aj obdĺžnik ho dedia — inak spolu nemajú nič spoločné.
  2. Ani v jednom z nich ale nie je napísané, ako sa posunúť o vektor. Tú prácu nemá v sebe ani kruh, ani obdĺžnik.
  3. Je v sluhovi. Ten ju vie spraviť pre čokoľvek, čo dedí Posunutelne — a sám nemá žiadny stav.
  4. Klient povie sluhovi: posuň tento kruh. Tvar mu podá ako parameter.
  5. Sluha zavolá kruh — spýta sa ho na polohu a nastaví novú. Robí to zvonku, cez rozhranie, do vnútra kruhu nesiaha.
  6. Teraz obdĺžnik. Klient volá to isté.
  7. A sluha robí to isté. Rovnaký kód, iná trieda — jediné, na čom mu záleží, je spoločné rozhranie.
  8. Všimni si smer. Sluha volá tvary, tvary nevolajú jeho — nemajú naň ani odkaz a o jeho existencii nevedia. Keby zmizol, nezmenil by sa v nich ani znak.
  9. Spoločné chovanie je na jednom mieste a nie je v ani jednej z tried, ktorých sa týka. Cena je v tom, že tvary musia zo seba vydať dosť na to, aby sa dali obslúžiť zvonku — a kto číta triedu Kruh, sa už nedozvie, čo všetko sa s ňou dá robiť.

Kedy použiť

  • To isté chovanie potrebuje viac tried, ktoré spolu inak nesúvisia. Vyčlení sa do sluhu a nemusí sa písať do každej z nich.
  • Do cudzích tried sa nedá zasiahnuť. Sluha pracuje zvonku cez ich rozhranie, takže knižnicu ani cudzí kód meniť netreba.
  • Chovanie do triedy významovo nepatrí. Kruh vie, kde je; posúvanie o vektor je operácia nad ním, nie jeho vlastnosť.
  • Operácií pribúda a triedy by narastali. Každá nová sa stane ďalším sluhom a obsluhované triedy zostanú, aké boli.

Pasce

  • Zamieňa sa s delegovaním. Kto deleguje, drží si pomocníka a volá ho; sluha je naopak ten, kto volá — obsluhované triedy oň ani nezavadia. Rovnaká dvojica, opačný smer.
  • Obsluhované triedy musia vydať dosť zo seba. Sluha potrebuje čítať aj meniť ich stav, takže rozhranie býva širšie, než by inak muselo byť — a zapuzdrenie tým trpí.
  • Spoločné rozhranie musí existovať. Bez neho sluha nemá čo volať a vzor sa rozpadne na sériu podmienok podľa typu.
  • Sluha nemá stav a ľahko sa z neho stane zberňa funkcií. Trieda plná nesúvisiacich operácií nad cudzími objektmi je len modul s procedúrami.
  • Chovanie sa vzdiali od dát. Kto číta triedu Kruh, nezistí, čo všetko sa s ňou dá robiť — to je rozsypané po sluhoch.
  • Pri jednej obsluhovanej triede je sluha zbytočný. Vzor sa oplatí až vtedy, keď je tried viac a majú spoločné rozhranie.