všetky vzory

State

Vymení chovanie objektu podľa toho, v akom stave sa práve nachádza.

class Stav {  dalej(objednavka) { throw new Error('abstraktná metóda'); }} class Nova extends Stav {  dalej(objednavka) {    zaplat();    objednavka.nastavStav(new Zaplatena());  }} class Zaplatena extends Stav {  dalej(objednavka) {    odosli();    objednavka.nastavStav(new Odoslana());  }} class Odoslana extends Stav {  dalej(objednavka) {    // koncový stav, ďalej sa už nikam neprepína  }} class Objednavka {  #stav = new Nova();   nastavStav(stav) {    this.#stav = stav;  }   // Ani jedna podmienka. O tom, čo sa stane, rozhoduje stav.  dalej() {    this.#stav.dalej(this);  }}

Celý priebeh v texte (11 krokov)
  1. Stav je abstraktný a tri konkrétne stavy ho dedia. Objednávka pozná len ten abstraktný — o Novej ani Odoslanej nevie nič.
  2. Objednávka práve vznikla, takže drží odkaz na stav Nova. Toto je jediné miesto, kde je jej stav uložený.
  3. Klient zavolá dalej(). Jediná metóda, žiadny parameter.
  4. Objednávka nerozhoduje o ničom — nemá ani jednu podmienku. Volanie posunie tomu, koho práve drží.
  5. A tu je vzor: stav sám rozhodne, čo bude ďalej, a vymení sa. Klient o tom nepovedal ani slovo — odkaz v komore sa zmenil bez neho.
  6. Klient zavolá dalej() znova. To isté volanie ako pred chvíľou.
  7. Objednávka ho posunie ďalej — lenže drží už iný stav, takže sa stane niečo iné. Objednávka sa pritom nezmenila ani o písmeno.
  8. A tento stav sa vymení za Odoslanú. Prechody sú napísané v stavoch, nie v objednávke.
  9. Tretie volanie, opäť to isté.
  10. Odoslana je koncový stav. Volanie prijme, ale nikam sa neprepne — odkaz v komore zostáva, na aký bol.
  11. To isté volanie urobilo zakaždým niečo iné a objednávka pritom nemá ani jednu podmienku. Prepnutie riadi stav — presne v tom sa vzor líši od Strategy, kde novú stratégiu podáva klient a kontext ju sám nikdy nevymení.

Kedy použiť

  • Objekt sa správa inak podľa toho, v akom je stave, a tých stavov je viac než dva. Každý sa stane triedou namiesto ďalšej vetvy v podmienke.
  • Tá istá podmienka sa opakuje vo viacerých metódach. Keď sa v každej z nich pýtate na to isté, je to stav, ktorý ešte nemá triedu.
  • Prechody medzi stavmi majú byť napísané a dodržané. Automat rozsypaný po podmienkach nikto neprečíta; automat z tried sa dá prejsť pohľadom.
  • Stavov pribúda. Nový stav znamená novú triedu a nie zásah do každej metódy, ktorá sa na stav pýta.

Pasce

  • Zamieňa sa so Strategy. Štruktúra je tá istá — kontext drží odkaz na abstrakciu — ale kto ten odkaz mení, je iné. Pri stratégii ho podá klient a kontext ho sám nikdy nevymení. Pri stave sa vymieňa sám, ako dôsledok volania, a stavy o sebe navzájom vedia.
  • Stavy sa navzájom poznajú. Každý musí vedieť, kto ide po ňom, takže sú previazané — a pridanie stavu doprostred znamená zásah do susedov.
  • Pri dvoch stavoch je vzor drahší než podmienka. Dve triedy a rozhranie namiesto jedného „if" sa oplatia až vtedy, keď stavov aj metód pribudne.
  • Prechod sa dá zabudnúť. Stav, ktorý sa neprepne, zasekne objekt navždy — a nič to nenahlási, lebo volanie prebehne úplne normálne.
  • Kde je stav uložený, je ďalšie rozhodnutie. Stavové objekty bez vlastných dát sa dajú zdieľať, so stavom musí každý kontext vlastný — a zmiešať to znamená tichú chybu.
  • Automat prestane byť vidieť ako celok. Prechody sú rozsypané po triedach, takže na otázku „ako sa dá dostať z A do C" odpovie iba prečítanie všetkých.