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.
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