9. diel - Statika
V predchádzajúcom cvičení, Riešené úlohy k 5.-8. lekciu OOP v Jave, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
Dnes sa v tutoriáli budeme venovať pojmu statika. Až doteraz sme boli zvyknutí, že dáta (stav) nesie inštancie. Atribúty, ktoré sme definovali, teda patrili inštancii a boli pre každú inštanciu jedinečné. OOP však umožňuje definovať atribúty a metódy na samotnej triede. Týmto prvkom hovoríme statické (niekedy triedne) a sú nezávislé na inštancii.
POZOR! Dnešná lekcia vám ukáže statiku, teda postupy,
ktoré v podstate narúšajú objektový model. OOP ich 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ť, pokiaľ si nie ste úplne istí, čo
robíte. Podobne, ako globálne premenné (ktoré Java našťastie nemá) je
statika v objektovom programovaní niečo, čo umožňuje písať zlý kód a
porušovať dobré praktiky. Dnes si ju teda skôr vysvetlíme, aby ste
pochopili určité metódy a triedy v Jave, ktoré ju používajú. Znalosti
použite s rozvahou, na svete bude menej zla.
Statické (triedne) atribúty
Ako statické môžeme označiť rôzne prvky. Začnime pri atribútoch. Ako
som sa už v úvode zmienil, statické prvky patria triede, nie inštancii.
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é atribúty sú
spoločné pre všetky inštancie triedy, ale nie je to presné, pretože s
inštanciami naozaj vôbec nesúvisia. Založme si nový projekt (názov napr.
Statika
) a urobme si jednoduchú triedu Uzivatel
:
Trieda je pomerne
jednoduchá, reprezentuje používateľov 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 užívateľ prihlásil, zavolá sa na ňom metóda
prihlasSe()
av jej parametri 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 hodnotu true
alebo false
podľa
toho, či prihlásenie prebehlo úspešne. V reáli by sa heslo ešte tzv. hashovalo, ale to tu
zabudneme.
Keď sa uží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ď užívateľa registrujeme, tak ešte nemáme k
dispozícii jeho inštanciu. Objekt nie je vytvorený a vytvorí sa až
po vyplnení formulára. Nemôžeme teda v triede Uzivatel
na tento
účel použiť verejný atribút 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ého atribútu pomocou modifikátora
static
:
Teraz sa presuňme do
Statika.java
a skúsme si atribút vypísať. K atribútu teraz
pristúpime priamo cez triedu:
Vidíme, že atribút skutočne patrí triede. Môžeme sa na neho pýtať v rôznych miestach programu bez toho, aby sme mali užívateľa vytvoreného.
Ako ďalšie praktické využitie statických atribútov sa ponúka
číslovanie užívateľov. Budeme chcieť, aby mal každý používateľ
pridelené unikátne identifikačné číslo. Bez znalosti statiky by sme si
museli strážiť zvonku každé vytvorenie užívateľa a počítať ich. My si
však môžeme vytvoriť priamo na triede Uzivatel
privátny
statický atribút dalsiId
, kde bude vždy pripravené číslo pre
ďalšieho užívateľa. Prvý používateľ bude mať id
na
hodnote 1, druhý id
na hodnote 2 a tak ďalej. Užívateľovi teda
pribudne nový atribút id
, ktorý sa v konštruktore nastaví
podľa hodnoty dalsiId
. Poďme si to vyskúšať:
Trieda si sama ukladá, aké
bude aj ďalšia jej inštancia. Toto id
priradíme novej
inštancii v konštruktore a zvýšime ho o 1
, aby bolo pripravené
pre ďalšiu inštanciu. Statické však nemusia byť len atribúty, možnosti
sú oveľa väčšie.
Statické 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. Veľa takýchto metód už poznáme, len sme si to
neuvedomovali. Nikdy sme napr. netvorili inštanciu triedy System
na to, aby sme do nej mohli zapisovať. Metóda println()
na
atribúte out
na triede System
je statická, rovnako
ako atribút samotný. Trieda System
je len jeden a bolo by
zbytočné tvoriť si z neho inštanciu, keď ho chceme používať. Podobne je
to napr. pri metóde round()
na triede Math
. Keď
chceme zaokrúhliť číslo, nebudeme si k tomu predsa tvoriť objekt. Ide teda
väčšinou o pomocné metódy, kde by inštanciácia zbytočne zdržiavala
alebo nedávala zmysel.
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. Za týmto účelom si vytvoríme pomocnú statickú
metódu zvalidujHeslo()
:
Opäť si skúsime, že
metódu môžeme na triede Uzivatel
zavolať:
Pozor! Vďaka tomu, že
metóda zvalidujHeslo()
patrí triede, nemôžeme v nej
pristupovať k žiadnym inštančným atribútom. Tieto atribúty
totiž neexistujú v kontexte triedy, ale inštancie. Pýtať sa na atribút
jmeno
by v našej metóde nemalo zmysel! Môžete si skúsiť, že
to naozaj nejde.
Rovnakú funkčnosť pri validácii hesla 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 používateľa by bola zbytočne rozdelená do dvoch
tried, keď môže byť za pomoci statiky pohromade.
Pri príklade so statickým atribútom minimalniDelkaHesla
sme
porušili zapuzdrenie, nemali by sme dovoľovať atribút nekontrolovane meniť.
Môžeme ho samozrejme nastaviť ako privátne a na jeho čítanie vytvoriť
statickú metódu. To napokon dobre poznáme z minulých dielov. Takúto metódu
doplníme aj pre vrátenie atribútu id
:
A vyskúšame si ešte
nakoniec naše metódy. Metóda main()
bude vyzerať takto:
A výstup bude:
Všimnite si, že aj metóda
main()
je statická, program totiž máme iba jeden. Z metódy
main()
môžeme volať aj len statické metódy v hlavnej triede
nášho programu. Viete teda pridávať metódy priamo do východiskovej triedy
s metódou main()
, čo však úplne nemá zmysel, pretože by sa
všetka logika mala odohrávať v zapuzdrených objektoch.
Privátny konštruktor
Pokiaľ sa nám vyskytne trieda, ktorá obsahuje len pomocné
metódy alebo nemá zmysel od nej tvoriť inštancie
(napr. nikdy nebudeme mať 2 konzoly), hovoríme o nej niekedy ako o statickej
triede. Java priamo neumožňuje priamo označiť triedu ako statickú, ale
tvorenie jej inštancie zakážeme pomocou implementácie privátneho
konštruktora. Takúto triedu potom nemožno
inštanciovať (vytvoriť jej inštanciu). Statická trieda, s ktorou
sme sa stretli, je napr. už spomínaná trieda Math
. Skúsme si
vytvoriť inštanciu statickej triedy Math
:
Dostaneme vyhubované, pretože má inštanciáciu zakázanú. Statická trieda má všetky prvky statické a teda nedáva zmysel od nej tvoriť inštanciu, tá by nič neobsahovala.
Niektoré jazyky podporujú aj statický konštruktor, ktorý sa potom zavolá vo chvíli, keď je trieda zaregistrovaná. Java statické konštruktory nepodporuje. Pokiaľ niektoré statické atribúty na triede potrebujú inicializáciu, môžeme pre nich vytvoriť statickú inicializačnú metódu, ktorú na triede potom niekedy za začiatku programu zavoláme.
Statický register
Poďme si takú jednoduchú statickú triedu vytvoriť. Mohlo by ísť o
triedu, ktorá obsahuje len pomocné metódy a atribúty (ako trieda
Math
). Ja som sa však rozhodol vytvoriť tzv. statický register.
Ukážeme si, ako je možné odovzdávať dôležité dáta medzi triedami bez
toho, aby sme museli mať inštanciu.
Majme aplikáciu, povedzme nejakú väčšiu a rozsiahlejšiu, napr. diár. Aplikácia bude obsahovať prepínanie jazyka jej rozhrania, farebnej schémy a či ju chceme spúšťať pri spustení operačného systému. Bude mať teda nejaké nastavenia, ku ktorým sa bude pristupovať z rôznych miest programu. Bez znalosti statiky by sme museli všetkým objektom (kalendári, úlohám, poznámkam...) odovzdať v konštruktore v akom jazyku pracujú, prípadne im dodať týmto spôsobom ďalšie nastavenia, ako prvý deň v týždni (nedeľa/pondelok), aká je farebná schéma a podobne .
Jednou z možností, ako toto riešiť, je použiť na uloženie týchto nastavení statickú triedu. Bude teda prístupná vo všetkých miestach programu a to aj bez vytvorenia inštancie. Obsahovať bude všetky potrebné nastavenia, ktoré si z nej budú objekty ľubovoľne brať. Mohla by vyzerať napr. nejako takto:
Všetky atribúty aj metódy
musia obsahovať modifikátor static
, všimnite si privátny
konštruktor. Zámerne som do triedy nedával verejné atribúty, ale vytvoril
metódy, aby sa hodnoty nedali meniť.
Skúsme si triedu teraz použiť, aj keď program diár nemáme. Vytvoríme si len na ukážku triedu Kalendar a skúsime si, že v nej máme naozaj bez problémov prístup k nastaveniu. Vložíme do nej metódu, ktorá vráti všetky nastavenia:
Následne všetko vypíšeme do konzoly:
Vidíme, že inštancia kalendára má naozaj bez problémov prístup ku všetkým nastaveniam programu.
Opäť pozor, tento kód je možné nesprávne použiť pre odovzdávanie nezapuzdrených dát a používa sa len v špecifických situáciách. Väčšina odovzdávania dát do inštancie prebieha pomocou parametra v konštruktore, nie cez statiku.
Statika sa veľmi často vyskytuje v návrhových vzoroch, o ktorých sme sa tu už bavili. Sú to postupy, ktoré dovádzajú objektovo orientované programovanie k dokonalosti ao ktorých sa tu určite ešte zmienime. Pre dnešok je toho však už dosť:) .
V nasledujúcom cvičení, Riešené úlohy k 9. lekcii OOP v Jave, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
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é 573x (20.11 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java