IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

Method Chaining a method Cascading

V dnešnom článku si vysvetlíme význam pomocných premenných v zdrojovom kóde a návrhový vzor Method Chaining s Fluent interface, ktorý implementácia tohto vzoru poskytuje. Vysvetlíme si tiež Method Cascading a v akých prípadoch nahrádza Method Chaining.

Motivácia

Tvorba pomocných premenných nie je vždy pre chod programu nevyhnutne potrebná, ale je dôležitá pre orientáciu programátora v zdrojovom kóde. Je bežnou praktikou vytvárať zbytočné premenné, ktoré program v podstate spomaľujú, ale umožňujú človeku čítať zdrojový kód. Niekedy však môžu byť aj na škodu a je užitočné sa ich zbaviť. Ukážme si príklady, kedy sa pomocné premenné oplatí používať a kedy už nie.

Užitočné pomocné premenné

Začnime kódom, ktorý je súčtom 2 čísla, ktoré sú zadané ako reťazce z konzoly a následne sú přeparsována na celočíselný typ int, Napočítava a vypísaná. Pomocných premenných si najprv vytvorme zbytočne veľa:

string vstup1 = Console.ReadLine();
string vstup2 = Console.ReadLine();
int a = int.Parse(vstup1);
int b = int.Parse(vstup2);
int c = a + b;
Console.WriteLine(c);

Premenné vstup1 a vstup2 sú tu v podstate zbytočné, môžeme sa ich jednoducho zbaviť, bez toho by to zhoršilo čitateľnosť zdrojového kódu:

int a = int.Parse(Console.ReadLine());
int b = int.Parse(Console.ReadLine());
int c = a + b;
Console.WriteLine(c);

Metódy sme zaboril do seba. Kód je teraz v ideálnej podobe, číta sa jednoducho zľava doprava. Ak by sme sa zanorovaním pokračovali, mohli by sme skončiť až s jednoriadkovým programom úplne bez pomocných premenných:

Console.WriteLine(int.Parse(Console.ReadLine()) + int.Parse(Console.ReadLine()));

Kód vyššie sa už však číta pomerne zle a určite by sme ho nemali takto písať. Nie je to z toho dôvodu, že je príliš veľa metód na jednom riadku, ale že sú metódy rekurzívne zanorené a musíme ich čítať zo stredu a pamätať si medzivýsledky.

Pozn .: Pri problémoch s výkonom sa môže na určitých miestach aplikácie niekedy vyplatiť začať sa pomocných premenných zbavovať. Takéto situácie však riešime vždy až nastanú, podľa poučky Premature optimization is the root of all evil.

Zbytočné pomocné premenné

Niekedy sú pomocné premenné ale iba na škodu. To je v prípadoch, keď potrebujeme nejako manipulovať stále s tým istým objektom a stále sa odkazovať na premennú s ním, alebo keď potrebujeme jeho inštanciu stále nejako upravovať. Uveďme si kód, ktorý zo zadaného reťazca vyreže prvých 50 znakov, odstráni okolo reťazca biele znaky a prevedie ho celý na malé písmená. Ako ozajstní zelenáči by sme si vytvorili pre každý mezivýstup samostatnú premennú, to my robiť už nebudeme. Stále by nás ale mohlo napadnúť výsledok přeukládat do pomocnej premennej:

string s = "Kdo je to Generál Failure a proč ten chlap čte zrovna z mého disku?";
s = s.Substring(0, 50);
s = s.Trim();
s = s.ToLower();

Stále opakovanie s = nemá z hľadiska čitateľnosti kódu žiadny význam a len zaberá miesto. Akékoľvek opakovanie v zdrojovom kóde je takmer vždy návrhová chyba (pozri poučka DRY).

Ďalšie zbytočné premenné

Premenné nám v zdrojovom kóde prekážajú aj v prípade, keď nastavujeme rôzne vlastnosti na jednom objekte:

Tlacitko tlacitko = new Tlacitko();
tlacitko.Text = "Ulozit";
tlacitko.Sirka = 100;
tlacitko.Vyska = 50;
tlacitko.Ramecek = 2;
tlacitko.Barva = Barva.Modra;
tlacitko.Ikona = Ikona.Disketa;
tlacitko.Vybrane = true;
tlacitko.Zkratka = {"ctrl", "s"};

Kód je zbytočne napučanie. Možno vás napadlo dať všetky parametre do konstruktoru, to by však prehľadnosti príliš nepomohlo, pretože by sme zabúdali ktorý je ktorý. Napr. hodnota 2 by pôsobila ako veľmi mätúce bez informácie, že sa jedná o rámček a za predpokladu, že by bolo okolo toľko ďalších hodnôt.

Ako z toho von?

Method Chaining

Reťazenie metód, niekedy označované aj ako Fluent interface, je technika volanie metódy bezprostredne na návratovej hodnote iné metódy, bez použitia pomocných premenných. Táto technika je možná iba za predpokladu, že objekt, na ktorom metódy voláme, s týmto používaním počíta, teda že vystavuje Fluent interface. Method Chaining je obvykle implementovaný tak, že metóda vracia buď priamo tú istú inštanciu objektu, na ktorom je volaná (teda vracia this), alebo vracia objekt s rovnakým rozhraním. Často je použitá na reťazcoch, na setter a na kolekciách. Nič samozrejme nebráni jej využitie na ďalších typoch objektov.

Určite ste si niekedy všimli, že na reťazcoch môžete volať metódy ako ToLower(), Substring(), Trim() a podobne za sebou, lebo vždy vracia reťazec a vykonáva sa na reťazci. V tejto chvíli ste použili tzv. Method Chaining, čiže zreťazenie metód. Pozrime sa, ako by vyzeral onen odstrašujúci príklad s metódami na reťazcami vyššie, keby sme ich prevolali za sebou:

string s = "Kdo je to Generál Failure a proč ten chlap čte zrovna z mého disku?";
s = s.Substring(0, 50).Trim().ToLower();

Výsledok je veľmi pôsobivý a stále skvele čitateľný, keďže metódy voláme zľava doprava.

Kolekcia

Method Chaining sa často využíva pri práci s kolekciami. Nemusí byť už alebo vracať tie isté dátové typy, len podporované rozhranie. V C # .NET by sme mohli z nejakej kolekcie za použitia Method Chaining vybrať plnoleté používateľa, zoradiť ich podľa veku, tie sa rovnakým vekom ešte podľa mena a vybrať ich mená. Vďaka Fluent interface to zvládneme na jedinom riadku:

var vysledek = uzivatele.Where(u => u.Vek >= 18).OrderBy(u => u.Vek).ThenBy(u => u.Jmeno).Select(u => u.Jmeno);

V príklade vyššie sa využíva fakt, že každú metódu voláme na kolekciu dát a jej výsledkom je opäť kolekcia dát. Môžeme teda volať ďalšiu metódu priamo na návratovej hodnote predošlej metódy. Výsledný zápis je veľmi prehľadný a pripomína otázky v jazyku SQL. Ak vás mätú operátormi šípok (=>), tak to je C# syntaxe pre lambda funkcie, anonymné metódy, pomocou ktorých sa špecifikuje čo od aké metódy chceme.

Setter

A čo príklad s instanciací tlačidlá a nastavovaním veľkého počtu jeho parametrov? Do triedy implementujeme setter podporujúce Fluent interface a parametre nastavíme pomocou nich:

Tlacitko tlacitko = new Tlacitko();
tlacitko.setText("Ulozit")
        .setSirka(100)
        .setVyska(50)
        .setRamecek(2)
        .setBarva(Barva.Modra)
        .setIkona(Ikona.Disketa)
        .setVybrane(true)
        .setZkratka({"ctrl", "s"});

Kód je teraz oveľa čitateľnejšie a kratšie. Danej metódy vnútri triedy Tlacitko by vyzerali asi takto:

public Tlacitko setText(string text)
{
    this.Text = text;
    return this;
}

public Tlacitko setSirka(int sirka)
{
    this.Sirka = sirka;
    return this;
}

public Tlacitko setVyska(int vyska)
{
    this.Vyska = vyska;
    return this;
}

public Tlacitko setRamecek(int ramecek)
{
    this.Ramecek = ramecek;
    return this;
}

// ...

Konštrukcia objektu sa spolu so setter často ešte vyčleňuje do samostatného objektu, tzv. Builder, čo zvyšuje čistotu kódu.

Method Cascading

Niektoré programovacie jazyky majú Method Chaining zabudovaný priamo vo svojej syntax, napr. Jazyk Dart. O tomto mechanizme potom hovoríme ako o tzv. Method Cascading. Zvyčajne je implementovaný cez operátor .. (dve bodky) a umožňuje nám pristupovať k vlastnostiam alebo volať metódy na objekte, bez toho aby sme ho museli znovu a znovu špecifikovať. Možno niektorí z vám pamätajú na konštrukciu with zo staručkého Pascalu, ktorá robila podobnú vec.

var tlacitko = new Tlacitko()
    ..text("Ulozit")
        ..sirka(100)
        ..vyska(50)
        ..ramecek(2)
        ..barva(Barva.Modra)
        ..ikona(Ikona.Disketa)
        ..vybrane(true)
        ..zkratka(["ctrl", "s"]);

Rovnako môžeme volať aj metódy a Method Chaining teda plne nahradiť, ak to náš programovací jazyk podporuje. Väčšina z nich to bohužiaľ ešte nevie a preto sa najčastejšie uchýlime k implementácii Fluent interface.


 

Všetky články v sekcii
Návrhové vzory
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity