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

10. diel - Getter, Setter a kaskádový operátor v Dart

V minulej lekcii, Statika v Dart , sme si vysvetlili statiku. V tomto Dart tutoriálu sa pozrieme na ďalšie prvky tried, ktoré ešte nepoznáme. Začnime sľúbeným Getter a setter.

Getter a setter

Veľmi často sa nám stáva, že chceme mať kontrolu nad zmenami nejaké vlastnosti objektu zvonku. Budeme chcieť vlastnosť nastaviť ako read-only alebo reagovať na jej zmeny. Založme si nový projekt (názov gettery_a_settery) a vytvorme nasledujúce triedu Student, ktorá bude reprezentovať študenta v nejakom informačnom systéme.

class Student {
    String jmeno;
    bool muz;
    int vek;
    bool plnolety;

    Student(this.jmeno, this.muz, this.vek) {
        plnolety = vek >= 18;
    }

    @override
    String toString() {
        String jsemPlnolety = 'jsem';
        if (!plnolety) jsemPlnolety = 'nejsem';
        String pohlavi = 'muž';
        if (!muz) pohlavi = 'žena';
        return 'Jsem $jmeno, $pohlavi. Je mi $vek let a $jsemPlnolety plnoletý.';
    }
}

Trieda je veľmi jednoduchá, študent sa nejako volá, je nejakého pohlavia a má určitý vek. Podľa tohto veku sa nastavuje vlastnosť plnolety pre pohodlnejšie vyhodnocovanie plnoletosti na rôznych miestach systému. Na uloženie pohlavia používame hodnotu typu bool, či je študent muž. Konštruktor podľa veku určí, či je študent plnoletý. Metóda toString() je navrhnutá pre potreby tutoriálu tak, aby nám vypísala všetky informácie. V reáli by vrátila pravdepodobne len meno študenta. Pomocou konstruktoru si nejakého študenta vytvorme:

Student s = new Student('Pavel Hora', true, 20);
print(s);

Výstup programu:

Konzolová aplikácia
Jsem Pavel Hora, muž. Je mi 20 let a jsem plnoletý.

Všetko vyzerá pekne, ale vlastnosti sú prístupné ako na čítanie, tak na zápis. Objekt teda môžeme rozbiť napríklad takto (hovoríme o nekonzistentnom vnútorným stave):

Student s = new Student('Pavel Hora', true, 20);
s.vek = 15;
s.muz = false;
print(s);

Výstup programu:

Konzolová aplikácia
Jsem Pavel Hora, žena. Je mi 15 let a jsem plnoletý.

Určite musíme ošetriť, aby sa plnoletosť obnovila pri zmene veku. Keď sa zamyslíme nad ostatnými vlastnosťami, nie je najmenší dôvod, aby sme ich taktiež umožňovali modifikovať. Študent si za normálnych okolností asi len ťažko zmení pohlavia alebo meno. Bolo by však zároveň vhodné ich vystaviť na čítanie, nemôžeme je teda iba nastaviť ako private. V skorších lekciách kurze sme na tento účel používali metódy, ktoré slúžili na čítanie privátnych vlastností. Ich názov sme volili ako vratJmeno() a podobne.

Pre zjednodušenie celého zápisu metód, ak máme veľmi jednoduché telo s jediným výrazom, môžeme použiť skrátenú syntax šípky (=>), za ktorú napíšeme daný výraz, ktorý bude metóda vracať. Nasledujúce metódy majú teda rovnakú funkcionalitu:

bool jeToPravda() => true;

bool jeToPravda() {
    return true;
}

Getter sú potom špeciálne metódy, ktoré označujeme kľúčovým slovom get. Getter vracia hodnotu. Navonok sa však netvári ako metódy, ale ako vlastnosti, tj. Potom používame napr. mujObjekt.jeToPravda, na čom vidíme, že sa nám nemení rozhrania triedy a vlastne ani nedokážeme zvonku zistiť, či používame vlastnosť alebo getter. Znovu si ukážeme oba dva spôsoby zápisu:

bool get jeToPravda => true;

bool get jeToPravda() {
    return true;
}

Setter sú špeciálne metódy, ktoré označujeme kľúčovým slovom set, návratový typ nastavujeme ako void. Majú práve jeden parameter - hodnotu. Aj setter môžeme zjednodušene zapísať pomocou šípky:

bool _jeToPravda = true;

void set jeToPravda(bool hodnota) => _jeToPravda = hodnota;

void set jeToPravda(bool hodnota) {
    _jeToPravda = hodnota;
}

Trieda by novo vyzerala napr. Nasledovne:

class Student {
    String _jmeno;
    bool _muz;
    int _vek;
    bool _plnolety;

    String get jmeno => _jmeno;

    bool get muz => _muz;

    int get vek => _vek;

    bool get plnolety => _plnolety;

    void set vek(int hodnota) {
        _vek = hodnota;
        _plnolety = hodnota >= 18;
    }

    Student(this._jmeno, this._muz, this._vek) {
        _plnolety = _vek >= 18;
    }

    @override
    String toString() {
        String jsemPlnolety = 'jsem';
        if (!plnolety) jsemPlnolety = 'nejsem';
        String pohlavi = 'muž';
        if (!muz) pohlavi = 'žena';
        return 'Jsem $jmeno, $pohlavi. Je mi $vek let a $jsemPlnolety plnoletý.';
    }
}

Vidíme, že Getter a setter v Dart sú veľmi jednoduché a elegantné. Nastavenie veku má už nejakú vnútornú logiku, pri jeho zmene musíme totiž prehodnotiť vlastnosť _plnolety. Zaistili sme, že sa do premenných nedá zapisovať inak, ako my chceme. Máme teda pod kontrolou všetky zmeny vlastností a dokážeme na ne reagovať. Nemôže sa stať, že by nám niekto vnútorný stav nekontrolovane menil a rozbil.

s.vek = 15; // nyní se změní i plnoletnost

Ak by sme chceli ešte lepšie upraviť našu triedu, môžeme celú vlastnosť _plnolety zahodiť a ponechať iba getter, ktorý bude podľa _vek vyhodnocovať stav (čím zjednodušíme aj setter vek a konštruktor):

class Student {
    String _jmeno;
    bool _muz;
    int _vek;

    String get jmeno => _jmeno;

    bool get muz => _muz;

    int get vek => _vek;

    bool get plnolety => vek >= 18;

    set vek(int hodnota) => _vek = hodnota;

    Student(this._jmeno, this._muz, this._vek);

    @override
    String toString() {
        String jsemPlnolety = 'jsem';
        if (!plnolety)
            jsemPlnolety = 'nejsem';
        String pohlavi = 'muž';
        if (!muz)
            pohlavi = 'žena';
        return 'Jsem $jmeno, $pohlavi. Je mi $vek let a $jsemPlnolety plnoletý.';
    }
}

Znovu zopakujem, že sme pôvodná vlastnosť s dátami nastavili na voľne neprístupnú a následne sme vytvorili špeciálne metódy (Getter a setter sa navonok tvári ako vlastnosti), ktoré hodnotu podmienečne nastavujú alebo vracajú. Naveky teda nemáme šancu spoznať, či pracujeme s obyčajnou vlastnosťou, alebo s Getter či setter. Getter a setter budeme od teraz používať stále, umožňujú nám totiž objekty dokonale zapouzdřit.

Celú triedu is ukážkovým programom si samozrejme opäť môžete stiahnuť pod článkom. Ešte si opäť vyskúšajme problémový príklad:

Student s = new Student('Pavel Hora', true, 20);
s.vek = 15;
// s.muz = false; // tento řádek nyní způsobí chybu a musí být odebrán
print(s);

Výstup programu:

Konzolová aplikácia
Jsem Pavel Hora, muž. Je mi 15 let a nejsem plnoletý.

Kaskádový operátor

Teraz, keď vieme, čo to sú vlastnosti, ako používať Getter a setter a metódy, je ten pravý čas na to ukázať si, ako si spríjemniť prácu pri volaní či nastavovaní dát objektu.

Aby sme si mohli pekne ukázať silu tohto operátora, zjednodušíme si pre tento príklad nášho študenta (a pre tentokrát zanedbáme, že to takto nie je ideálne):

class Student {
    String jmeno;
    bool muz;
    int vek;
    bool get plnolety => vek >= 18;

    @override
    String toString() {
        String jsemPlnolety = 'jsem';
        if (!plnolety) jsemPlnolety = 'nejsem';
        String pohlavi = 'muž';
        if (!muz) pohlavi = 'žena';
        return 'Jsem $jmeno, $pohlavi. Je mi $vek let a $jsemPlnolety plnoletý.';
    }
}

Ak by sme chceli takéhoto študenta nastaviť, pravdepodobne by sme robili niečo takéhoto:

Student jarda = new Student();
jarda.jmeno = 'Jarda';
jarda.muz = true;
jarda.vek = 21;

Asi sami vidíte, že je zápis až príliš zdĺhavý a nepekný. Dart má pre tieto účely báječný kaskádový operátor (dvojbodka ..), ktorým sa vyvarujeme repetitivního písania premenné. Používať ho môžeme tak na vlastnosti, tak i na metódy. Tento operátor prevedie danej nastavenie či zavolanie a následne vracia objekt. Rovnaký kód by sme tak napísali nejako takto:

Student jarda = new Student()
    ..jmeno = 'Jarda'
    ..muz = true
    ..vek = 21;

Nezabúdajme ale na pravidlo, že čitateľnosť kódu je podstatnejšie než kratšie zápis a môžu nastať situácie, kedy aj použitie kaskádového operátorovi nebude vhodné.

V budúcej lekcii, Dátum a čas v Dart , sa pozrieme ako sa v Dart pracuje s dátumom a časom.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 4x (2.48 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Dart

 

Predchádzajúci článok
Statika v Dart
Všetky články v sekcii
Objektovo orientované programovanie v Dart
Preskočiť článok
(neodporúčame)
Dátum a čas v Dart
Článok pre vás napísal Honza Bittner
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
FIT ČVUT alumnus :-) Sleduj mě na https://twitter.com/tenhobi a ptej se na cokoli na https://github.com/tenhobi/ama.
Aktivity