10. diel - Gettery a settery v Jave
V predchádzajúcom cvičení, Riešené úlohy k 9. lekcii OOP v Jave, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
Dnes sa v tutoriáli pozrieme na tzv. gettery a settery.
Gettery a settery
Veľmi často sa nám stáva, že chceme mať kontrolu nad zmenami nejakého
atribútu objektu zvonku. Budeme chcieť atribút nastaviť ako
read-only (len na čítanie) alebo reagovať na jeho zmeny. Založme si
nový projekt s názvom napr. GetSet
a vytvorme nasledujúcu triedu
Student
, ktorá bude reprezentovať študenta v nejakom
informačnom systéme:
Trieda je veľmi jednoduchá,
študent sa nejako volá, je nejakého pohlavia a má určitý vek. Podľa tohto
veku sa nastavuje atribút plnolety
pre pohodlnejšie
vyhodnocovanie plnoletosti na rôznych miestach systému. Na uloženie pohlavia
používame hodnotu typu boolean
, č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 konštruktora si nejakého študenta vytvorme:
Výstup:
Všetko vyzerá pekne, ale atribúty sú prístupné ako na čítanie, tak na zápis. Objekt teda môžeme rozbiť napríklad takto (hovoríme o nekonzistentnom vnútornom stave):
Výstup:
Určite musíme ošetriť,
aby sa plnoletosť obnovila pri zmene veku. Keď sa zamyslíme nad ostatnými
atribútmi, nie je najmenší dôvod, aby sme taktiež umožňovali modifikovať
pohlavie. Bolo by však zároveň vhodné ich vystaviť na čítanie, nemôžeme
ich teda iba nastaviť ako private
. V skorších dieloch seriálu
sme na tento účel používali metódy, ktoré slúžili na čítanie
privátnych atribútov. Ich názov sme volili ako vratVek()
a pre
nastavenie atribútu napríklad nastavVek()
. V Jave sa všetky
atribúty, s ktorými sa má pracovať zvonku, označujú ako privátne a pre
prístup k nim sa definujú práve podobné metódy. Na ich pomenovanie sa
ustálilo getNazevAtributu()
na čítanie a
setNazevAtributu()
na zápis. Ak je atribút typu
boolean
, volá sa getter isNazevAtributu()
. Trieda by
novo vyzerala napr. takto:
Metódy, čo hodnoty iba
vracajú, sú veľmi jednoduché. Nastavenie veku má už nejakú vnútornú
logiku, pri jeho zmene musíme totiž prehodnotiť atribút
plnolety
. Zaistili sme, že sa do premenných nedá zapisovať
inak, než my chceme. Máme teda pod kontrolou všetky zmeny atribútov a
dokážeme na ne reagovať. Nemôže sa stať, že by nám niekto vnútorný
stav nekontrolovane menil a rozbil. Všimnite si aj zmeny v konštruktore, kde
sa nastavuje vek metódou setVek()
.
Metódam na vrátenie hodnoty sa hovorí gettery a metódam
pre zápis settery. Pre editáciu ostatných atribútov by sme
urobili jednu metódu editujStudenta()
, ktorá by bola podobná
konštruktoru.
Otázkou je, aká je teraz výhoda toho, že je atribút jmeno
privátne, keď do neho ide zapisovať a možno z neho aj čítať. Veď máme v
kóde zbytočne 2 metódy, ktoré tam zaberajú miesto a ešte je to
pomalé?
Naozaj sme to napísali správne, alebo aspoň tak, ako sa to bežne robí. Java pred kompiláciou vykonáva početné optimalizácie a pokiaľ sú metódy tak jednoduché, že iba vracajú hodnotu alebo ju nastavujú, metóda sa skompiluje ako priamy prístup do pamäte. Sú teda rovnako rýchle, ako keby sme pracovali s verejným atribútom (za predpokladu, že setter alebo getter nemá nejakú ďalšiu logiku).
IDE dokáže gettery a settery automaticky generovať, nemusíme ich teda otrocky opisovať. Stačí na privátnu premennú kliknúť pravým tlačidlom a zvoliť položku Refactor -> Encapsulate fields:
-
V ďalšom dialógu si zaškrtneme, ku ktorým atribútom chceme vygenerovať gettery a settery. My nebudeme chcieť sprístupniť pre zápis atribúty
plnolety
amuz
. Atribútplnolety
pôjde zmeniť len zmenením veku študenta. Pohlavie nedáva zmysel meniť vôbec (pokiaľ by to bolo naozaj niekedy potrebné, bola by na to nejaká špeciálna metóda, aby sa vylúčila zmena chybou v kóde). Dialóg potvrdíme:Settery pre atribúty
plnolety
amuz
z triedy teda odstránime. -
V ďalšom dialógu si zaškrtneme, ku ktorým atribútom chceme vygenerovať gettery a ku ktorým settery. My nebudeme chcieť sprístupniť pre zápis atribúty
plnolety
amuz
. Atribútplnolety
pôjde zmeniť len tak, že zmeníme vek študenta. Pohlavie nedáva zmysel meniť vôbec (pokiaľ by to bolo naozaj niekedy potrebné, bola by na to nejaká špeciálna metóda, aby sa vylúčila zmena chybou v kóde). Dialóg potvrdíme:
Hlavným dôvodom je určitá štandardizácia. Nemusíme premýšľať nad
tým, či je daná vlastnosť objektu riešená cez getter alebo atribút, na
inštanciu jednoducho vždy voláme metódu začínajúcu slovom
get
(prípadne is
) pokiaľ chceme vlastnosť
inštancie čítať, prípadne metódu začínajúcu set
, ak ju
chceme zmeniť.
Ďalšou výhodou je, že keď sa v budúcnosti rozhodneme, že nejaký atribút chceme urobiť read-only (len na čítanie), jednoducho zmažeme setter. Nemusíme vytvárať getter a meniť viditeľnosť atribútu, čo by zmenilo rozhranie triedy a rozbilo existujúci kód, ktorý by ju používal.
Gettery a settery teda budeme odteraz používať pri všetkých
atribútoch, ktoré majú byť zvonku prístupné. V našich triedach
sa takmer nebudú vyskytovať atribúty s viditeľnosťou
public
.
Skúsme si teraz ešte spustiť kód, ktorý predtým rozbil interný stav objektu:
Výstup je už v poriadku:
V nasledujúcom kvíze, Kvíz - Dedičnosť, statika, gettery a settery v Jave OOP, si vyskúšame 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é 635x (9.02 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java