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

9. diel - Statika v Dart

V minulej lekcii, Aréna s mágom (dedičnosť a polymorfizmus) , sme si v praxi vyskúšali dedičnosť a polymorfizmus, teraz sa budeme venovať pojmu statika. Až doteraz sme boli zvyknutí, že dáta (stav) nesie inštancie. Vlastnosti, ktoré sme definovali, teda patrili inštanciu a boli pre každú inštanciu jedinečné. OOP však umožňuje definovať vlastnosti a metódy na samotnej triede. Týmto prvkom hovoríme statické (niekedy triednej) a sú nezávislé na inštanciu.

Objektovo orientované programovanie v Dart
POZOR! Táto lekcia vám ukáže statiku, teda postupy, ktoré v podstate narušujú objektový model. OOP je obsahuje len pre špeciálne prípady a všeobecne platí, že všetko ide napísať bez statiky. Vždy musíme starostlivo zvážiť, či statiku naozaj nutne potrebujeme. Všeobecne by som odporúčal statiku vôbec nepoužívať, ak si nie ste úplne istí, čo robíte. Podobne, ako globálne premenné je statika v objektovom programovaní niečo, čo umožňuje písať zlý kód a porušovať dobré praktiky. V tejto lekcii si ju teda skôr vysvetlíme, aby ste pochopili určité metódy a triedy v Dart, ktoré ju používajú. Znalosti použite s rozvahou, na svete bude potom menej zla.

Statické (triedny) vlastnosti

Ako statické môžeme označiť rôzne prvky. Začnime u vlastností. Ako som sa už v úvode spomenul, statické prvky patrí triede, nie inštanciu. Dáta v nich uložené teda môžeme čítať bez ohľadu na to, či nejaká inštancia existuje. V podstate môžeme povedať, že statické vlastnosti sú spoločné pre všetky inštancie triedy, ale nie je to presné, pretože s inštanciami naozaj vôbec nesúvisí. Založme si nový projekt (s názvom napr. Statika) a urobme si jednoduchú triedu Uzivatel:

class Uzivatel {
    String _jmeno;
    String _heslo;
    bool _prihlaseny;

    Uzivatel(this._jmeno, this._heslo) {
        _prihlaseny = false;
    }

    bool prihlasSe(String zadaneHeslo) {
        if (zadaneHeslo == _heslo) {
            _prihlaseny = true;
        return true;
    } else
        return false; // hesla nesouhlasí
    }
}

Trieda je pomerne jednoduchá, reprezentuje používateľa nejakého systému. Každá inštancia používateľa má svoje meno, heslo a tiež sa o ňu vie, či je prihlásená alebo nie. Aby sa používateľ prihlásil, zavolá sa na ňom metóda prihlasSe() a v jej parametra heslo, ktoré človek za klávesnicou zadal. Metóda overí, či ide naozaj o tohto používateľa a pokúsi sa ho prihlásiť. Vráti true / false podľa toho, či prihlásenie prebehlo úspešne. V reáli by sa Vaše heslo ešte tzv. Hashovalo, ale to tu vynecháme.

Keď sa používateľ registruje, systém mu napíše, akú minimálnu dĺžku musí jeho heslo mať. Toto číslo by sme mali mať niekde uložené. Vo chvíli, keď používateľa registrujeme, tak ešte nemáme k dispozícii jeho inštanciu. Objekt nie je vytvorený a vytvoria sa až po vyplnení formulára. Nemôžeme teda v triede Uzivatel na tento účel použiť verejnú vlastnosť minimalniDelkaHesla. Samozrejme by bolo veľmi prínosné, keby sme mali údaj o minimálnej dĺžke hesla uložený v triede Uzivatel, pretože k nemu logicky patrí. Údaj uložíme do statické vlastnosti pomocou modifikátora static:

class Uzivatel {
    String _jmeno;
    String _heslo;
    bool _prihlaseny;

    static int minimalniDelkaHesla = 6;

    // ...
}

Teraz sa presuňme do main.dart a skúsme si vlastnosť vypísať. K vlastnosti teraz pristúpime priamo cez triedu:

print(Uzivatel.minimalniDelkaHesla);

Výstup programu:

Konzolová aplikácia
6

Vidíme, že vlastnosť naozaj patrí triede. Môžeme sa na ňu pýtať v rôznych miestach programu bez toho, aby sme mali používateľa vytvoreného. Naopak na inštanciu užívateľa túto vlastnosť nenájdeme:

Uzivatel u = new Uzivatel('Tomáš Marný', 'heslojeveslo');
print(u.minimalniDelkaHesla);

dartanalyzer zahlási chybu a kód sa nespustí.

Ako ďalšie praktické využitie statických vlastností sa ponúka číslovanie používateľov. Budeme chcieť, aby mal každý užívateľ pridelené unikátne identifikačné číslo. Bez znalosti statiky by sme si museli strážiť zvonku každej vytvorenie užívateľa a počítať je. My si však môžeme vytvoriť priamo na triede Uzivatel privátne statickú vlastnosť dalsiId, kde bude vždy pripravené číslo pre ďalšieho užívateľa. Prvý užívateľ bude mať id 1, druhý 2 a tak ďalej. Používateľovi teda pribudne nová vlastnosť _id, ktorá sa v konstruktoru nastaví podľa hodnoty _dalsiId. Poďme si to vyskúšať:

class Uzivatel {
    String _jmeno;
    String _heslo;
    bool _prihlaseny;
    int _id;

    static int minimalniDelkaHesla = 6;
    static int _dalsiId = 1;

    Uzivatel(this._jmeno, this._heslo) {
        _prihlaseny = false;
        _id = _dalsiId;
        _dalsiId++;
    }

    // ...
}

Trieda si sama ukladá, aké bude _id ďalší jej inštancie. Toto _id priradíme nové inštanciu v konstruktoru a zvýšime ho o 1, aby bolo pripravené pre ďalšiu inštanciu. Statické však nemusí byť len vlastnosti, možnosti sú oveľa väčšie.

Statickej metódy

Statické metódy sa volajú na triede. Ide najmä o pomocné metódy, ktoré potrebujeme často používať a neoplatí sa nám tvoriť inštanciu. Mnoho takýchto metód už poznáme, len sme si to neuvedomovali. Nikdy sme si napríklad nevytvorili inštanciu na parsovanie reťazca do položky (int.parse()). Niektoré vlastnosti, či metódy však nie sú statické, aj keď sa to tak môže zdať. Väčšina vecí z knižníc Dart sú tzv. "First class citizens", čo v podstate znamená, že po importovaní knižnice máte k dispozícii už vytvorenú inštanciu (napr. stdout) alebo metódu (napr. print()) na použitie.

Ukážme si opäť reálny príklad. Pri registrácii používateľa potrebujeme poznať minimálnu dĺžku hesla ešte pred jeho vytvorením. Bolo by tiež dobré, keby sme mohli pred jeho vytvorením aj heslo skontrolovať, či má správnu dĺžku, neobsahuje diakritiku, je v ňom aspoň jedno číslo a podobne. Na tento účel si vytvoríme pomocnú statickú metódu zvalidujHeslo():

static bool zvalidujHeslo(String heslo) {
    if (heslo.length >= minimalniDelkaHesla) {
        // podrobnou logiku validace hesla vynecháme
        return true;
    }
    return false;
}

Opäť si skúsime, že metódu môžeme na triede Uzivatel zavolať:

print(Uzivatel.zvalidujHeslo('heslojeveslo'));

Pozor! Vďaka tomu, že metóda zvalidujHeslo() náleží triede, nemôžeme v nej pristupovať k žiadnym inštančným vlastnostiam. Tieto vlastnosti totiž neexistujú v kontexte triedy, ale inštancie. Pýtať sa na _jmeno by v našej metóde nemalo zmysel! Môžete si skúsiť, že to naozaj nejde.

Rovnaké funkčnosti pri validácii heslá samozrejme môžeme dosiahnuť aj bez znalosti statiky. Vytvorili by sme si nejakú triedu, napr. ValidatorUzivatelu a do nej napísali tieto metódy. Museli by sme potom vytvoriť jej inštanciu, aby sme metódy mohli volať. Bolo by to trochu mätúce, pretože logika užívateľa by bola zbytočne rozdelená do dvoch tried, keď môže byť za pomoci statiky pohromade.

U príklade sa statickou vlastností minimalniDelkaHesla sme porušili zapuzdrenie, nemali by sme dovoľovať vlastnosť nekontrolovane meniť. Môžeme ju samozrejme nastaviť ako privátne ak jej čítaní vytvoriť statickú metódu. To ostatne dobre poznáme z minulých dielov. Takúto metódu doplníme aj pre navrátenie id:

static int vratMinimalniDelkuHesla() {
    return minimalniDelkaHesla;
}

int vratId() {
    return _id;
}

A vyskúšame si ešte nakoniec naše metódy. main.dart bude vyzerať takto:

Uzivatel u = new Uzivatel('Tomáš Marný', 'heslojeveslo');
print('ID prvního uživatele: ${u.vratId()}');
Uzivatel v = new Uzivatel('Olí Znusinudle', 'csfd1fg');
print('ID druhého uživatele: ${u.vratId()}');
print('Minimální délka hesla uživatele je: ${Uzivatel.vratMinimalniDelkuHesla()}');
print('Validnost hesla "heslo" je: ${Uzivatel.zvalidujHeslo('heslo')}');

Výstup programu:

Konzolová aplikácia
ID prvního uživatele: 1
ID druhého uživatele: 1
Minimální délka hesla uživatele je: 6
Validnost hesla "heslo" je: false

Statika sa veľmi často vyskytuje v návrhových vzoroch, o ktorých sme sa tu už bavili. Sú to postupy, ktoré dovádza objektovo orientované programovanie k dokonalosti ao ktorých sa tu určite ešte zmienime. Pre túto lekciu je toho však už dosť:) V budúcej lekcii, Getter, Setter a kaskádový operátor v Dart , sa pozrieme na vlastnosti v Dart.


 

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é 3x (2.42 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Dart

 

Predchádzajúci článok
Aréna s mágom (dedičnosť a polymorfizmus)
Všetky články v sekcii
Objektovo orientované programovanie v Dart
Preskočiť článok
(neodporúčame)
Getter, Setter a kaskádový operátor 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