Reťazenie metód (Method Chaining)

Nejde o žiadnu veľkú vec, skôr nápravu drobnej nepríjemnosti pri písaní kódu v objektovo orientovaných jazykoch.

V objektovo orientovaných jazykoch (veľmi zjednodušene povedané) má každý príkaz dve časti: kto to má urobiť, a čo má urobiť. To je väčšinou fajn, ale niekedy nastane situácia, keď zadávame veľa príkazov tomu istému objektu.

Predstavme si jednoduchú aplikáciu vo fiktívnom programovacom jazyku. Máme dve tlačidlá, ktoré robia nejaké dôležité úkony s dátami (tieto úkony nazvime jednoducho "funkcia číslo 1" a "funkcia číslo 2"), plus dve štandardné tlačidlá "OK" a "Storno". Asi budete súhlasiť, že väčšina dialógových okien je omnoho zložitejšia. Napriek tomu, pozrite na ten kód...

dialóg.nastavŠírku(800);
dialóg.nastavVýšku(600);
Tlačidlo funkcia1 = nové Tlačidlo();
funkcia1.nastavSúradnicuX(330);
funkcia1.nastavSúradnicuY(260);
funkcia1.nastavŠírku(140);
funkcia1.nastavVýšku(20);
funkcia1.nastavNápis("Funkcia číslo 1");
funkcia1.nastavFunkciuPoKliknutí(zavolanieFunkcieČíslo1);
Tlačidlo funkcia2 = nové Tlačidlo();
funkcia1.nastavSúradnicuX(330);
funkcia2.nastavSúradnicuY(290);
funkcia2.nastavŠírku(140);
funkcia2.nastavVýšku(20);
funkcia2.nastavNápis("Funkcia číslo 2");
funkcia2.nastavFunkciuPoKliknutí(zavolanieFunkcieČíslo2);
Tlačidlo okej = nové Tlačidlo();
okej.nastavSúradnicuX(620);
okej.nastavSúradnicuY(570);
okej.nastavŠírku(80);
okej.nastavVýšku(20);
okej.nastavNápis("OK");
okej.nastavFunkciuPoKliknutí(uloženieÚdajovAZatvorenieOkna);
Tlačidlo storno = nové Tlačidlo();
storno.nastavSúradnicuX(710);
storno.nastavSúradnicuY(570);
storno.nastavŠírku(80);
storno.nastavVýšku(20);
storno.nastavNápis("Storno");
storno.nastavFunkciuPoKliknutí(zatvorenieOkna);

Asi budete súhlasiť, že tento kód vyzerá dosť neprehľadne. A pritom nerobí nič sofistikované. Navyše, daný kód obsahuje jednu chybu; skúste ju v tej hromade písmeniek nájsť.

Čo s tým?

Samozrejme, v tejto konkrétnej situácii je veľa vecí, ktoré by sa dali vylepšiť. Keby sme metódy "nastavSúradnicuX(x)" a "nastavSúradnicuY(y)" spojili do jednej metódy "nastavSúradnice(x, y)"; a podobne aj "nastavŠírku(šírka)" a "nastavVýšku(výška)" do "nastavVeľkosť(šírka, výška)", bolo by tých volaní o čosi menej. Mohli by sme využiť, že všetky tlačidlá majú rovnakú výšku. Mohli by sme vytvoriť grafický editor, v ktorom by sme si tlačidlá nakreslili a uložili do osobitného súboru.

Skúsme však na chvíľu zabudnúť, že ide o tlačidlá. (Rovnako by to mohol byť e-mail, ktorému nastavujeme odosielateľa, adresáta, nadpis, text správy, digitálny podpis, atď.) Sústreďme sa na to, že niekoľkokrát po sebe voláme metódy toho istého objektu. Navyše, žiadna z týchto metód nevracia výsledok. Vyzerajú asi takto:

metóda Tlačidlo.nastavSúradnicuX(x) {
  tentoObjekt.súradnicaX = x;
}

Upravme tieto metódy bez výsledku tak, aby ako výsledok vracali pôvodný objekt. Samotný program zatiaľ vôbec nemusíme meniť, pretože nevyužitá návratová funkcia sa jednoducho ignoruje.

metóda Tlačidlo.nastavSúradnicuX(x) {
  tentoObjekt.súradnicaX = x;
  výsledok tentoObjekt;
}

Teraz môžeme pôvodný program upraviť tak, že keď postupne voláme viacero metód toho istého objektu, napíšeme meno objektu iba pri prvom volaní. Pri každom ďalšom volaní využijeme, že predchádzajúca metóda vrátila pôvodný objekt, za ktorý stačí doplniť bodku. Všimnime si, že aj konštruktor vracia ako hodnotu vytvorený objekt. Preto:

dialóg.nastavŠírku(800)
      .nastavVýšku(600);
Tlačidlo funkcia1 = nové Tlačidlo()
  .nastavSúradnicuX(330)
  .nastavSúradnicuY(260)
  .nastavŠírku(140)
  .nastavVýšku(20)
  .nastavNápis("Funkcia číslo 1")
  .nastavFunkciuPoKliknutí(zavolanieFunkcieČíslo1);
Tlačidlo funkcia2 = nové Tlačidlo()
  .nastavSúradnicuX(330)
  .nastavSúradnicuY(290)
  .nastavŠírku(140)
  .nastavVýšku(20)
  .nastavNápis("Funkcia číslo 2")
  .nastavFunkciuPoKliknutí(zavolanieFunkcieČíslo2);
Tlačidlo okej = nové Tlačidlo()
  .nastavSúradnicuX(620)
  .nastavSúradnicuY(570)
  .nastavŠírku(80)
  .nastavVýšku(20)
  .nastavNápis("OK")
  .nastavFunkciuPoKliknutí(uloženieÚdajovAZatvorenieOkna);
Tlačidlo storno = nové Tlačidlo()
  .nastavSúradnicuX(710)
  .nastavSúradnicuY(570)
  .nastavŠírku(80)
  .nastavVýšku(20)
  .nastavNápis("Storno")
  .nastavFunkciuPoKliknutí(zatvorenieOkna);

Nový program je o čosi prehľadnejší než starý. Nedá sa v ňom omylom urobiť rovnaká chyba ako v pôvodnom programe. (Ak ste ju nenašli, spočívala v tom, že v jednom z volaní týkajúcich sa objektu "funkcia2" bolo omylom napísané "funkcia1". Takáto chyba môže ľahko vzniknúť pri písaní alebo kopírovaní časti kódu, a v takomto prípade sa nedá automaticky odhaliť.) Všimnite si, ako z konca mnohých riadkov zmizli bodkočiarky; z hľadiska programovacieho jazyka teraz tieto riadky tvoria jeden zložený príkaz.

Zhrnutie:

Reťazenie metód môžeme využiť vtedy, keď:

  • často voláme niekoľko metód toho istého objektu tesne po sebe;
  • tieto metódy nepotrebujú vrátiť žiaden zmysluplný výsledok.

Reťazenie metód nemôžeme použiť vtedy, keď metóda vracia nejakú zmysluplnú hodnotu. Napríklad metóda na nastavenie súradnice X nepotrebuje vrátiť žiadnu hodnotu, ale metóda na zistenie súradnice X už vracia hodnotu: súradnicu X daného tlačidla. Nemôže zároveň vrátiť súradnicu X aj samotné tlačidlo.

Niekedy aj metódy na nastavovanie hodnôt vracajú výsledok; napríklad či sa danú hodnotu podarilo alebo nepodarilo nastaviť. V takom prípade je ale lepšie na oznámenie neúspechu namiesto návratovej hodnoty použiť výnimku, ak to príslušný programovací jazyk umožňuje. Sú ale aj iné situácie.

Tak ako všetky programátorské techniky, aj reťazenie metód treba používať s rozvahou. Nemusíte teraz prepisovať každú metódu, ktorá doteraz nevracala žiadnu hodnotu. Stačí to robiť vtedy, keď to má zmysel; keď sa dané metódy volajú často, a zvyčajne viaceré pre ten istý objekt.

Niektoré programovacie jazyky, ako napríklad Smalltalk, poskytujú reťazenie metód automaticky; ak nie je napísané, akú hodnotu metóda vracia, je to automaticky volaný objekt. Iné programovacie jazyky (JavaScript) zase vracajú nedefinovanú hodnotu. V ďalších (Java) je zase povinné v každej metóde vrátiť výsledok explicitne. Zistite si, ako je to vo vašom programovacom jazyku.

viliam@bur.sk