Slevový týden - Březen C# týden
Využij náš slevový týden a získej až 30 % bodů navíc zdarma! Zároveň také probíhá C# týden se slevou na e-learning až 80 %
Hledáme fulltime programátora do ITnetwork týmu -100% homeoffice, 100% časově flexibilní #bezdeadlinu Mám zájem!

7. diel - Dedičnosť a polymorfizmus

V minulej lekcii, Java - Aréna s bojovníkmi , sme dokončili našu arénu, simulujúce zápas dvoch bojovníkov. Dnes si opäť rozšírime znalosti o objektovo orientovanom programovaní. V úvodnom tutoriále do OOP sme si hovorili, že OOP stojí na troch základných pilieroch: zapuzdrenie, dedičnosti a polymorfizmu. Zapuzdrenie a používanie modifikátora private nám je už dobre známe. Dnes sa pozrieme na zvyšné dva piliere.

Dedičnosť

Dedičnosť je jedna zo základných vlastností OOP a slúži k tvoreniu nových dátových štruktúr na základe starých. Vysvetlime si to na jednoduchom príklade:

Budeme programovať informačný systém. To je celkom reálny príklad, aby sme si však učenie spríjemnili, bude to informačný systém pre správu zvierat v ZOO :) Náš systém budú používať dva typy užívateľov: užívateľ a administrátor. Užívateľ je bežný ošetrovateľ zvierat, ktorý bude môcť upravovať informácie o zvieratách, napr. Ich váhy alebo rozpätie krídel. Administrátor bude môcť tiež upravovať údaje o zvieratách a navyše zvieratá pridávať a mazať z databázy. Z atribútov bude mať navyše telefónne číslo, aby ho bolo možné kontaktovať v prípade výpadku systému. Bolo by určite zbytočné a neprehľadné, keby sme si museli definovať obe triedy úplne celé, pretože mnoho vlastností týchto 2 objektov je spoločných. Užívateľ aj administrátor budú mať určite meno, vek a budú sa môcť prihlásiť a odhlásiť. Nadefinujeme si teda iba triedu Uzivatel (nepôjde o funkčné ukážku, dnes to bude len teória, programovať budeme nabudúce):

class Uzivatel {
    private String jmeno;
    private String heslo;
    private int vek;

    public boolean prihlasit(String heslo) {
        ...
    }

    public boolean odhlasit() {
        ...
    }

    public void nastavVahu(Zvire zvire) {
        ...
    }

    ...
}

Triedu som len naznačil, ale iste si ju dokážeme dobre predstaviť. Bez znalosti dedičnosti by sme triedu Administrator definovali asi takto:

class Administrator {
    private String jmeno;
    private String heslo;
    private int vek;
    private String telefonniCislo;

    public boolean prihlasit(String heslo) {
        ...
    }

    public boolean odhlasit() {
        ...
    }

    public void nastavVahu(Zvire zvire) {
        ...
    }

    public void pridejZvire(Zvire zvire) {

    }

    public void vymazZvire(Zvire zvire) {

    }

    ...
}

Vidíme, že máme v triede veľa redundantného (duplikovaného) kódu. Akékoľvek zmeny musíme teraz vykonávať v oboch triedach, kód sa nám veľmi komplikuje. Teraz použijeme dedičnosť, definujeme teda triedu Administrator tak, aby z triedy Uzivatel dedila. Atribúty a metódy užívateľa teda už nemusíme znovu definovať, Java nám ich do triedy sám dodá:

class Administrator extends Uzivatel
{
    private String telefonniCislo;

    public void pridejZvire(Zvire zvire) {

    }

    public void vymazZvire(Zvire zvire) {

    }

    ...
}

Vidíme, že ku zdedenie sme použili kľúčové slovo "Extends". V anglickej literatúre nájdete dedičnosť pod slovom inheritance.

V príklade vyššie nebudú v potomkovi prístupné privátnej atribúty, ale iba atribúty a metódy s modifikátorom public. Private atribúty a metódy sú chápané ako špeciálne logika konkrétnej triedy, ktorá je potomkovi utajená, aj keď ju vlastne používa, nemôže ju meniť. Aby sme dosiahli požadovaného výsledku, použijeme nový modifikátor prístupu protected.

Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

Protected sprístupní atribút alebo metódu buď ľubovoľným potomkom v akomkoľvek balíčku alebo ľubovoľným triedam v tom istom balíčku. Potomok sa teda už k atribútu dostane. Ako problém môže byť, že atribút je zvonku viditeľný, preto sa v súbore .java sa triedou často používa iné meno balíčka, než v ktorom sú ostatné časti programu. Tento nový balík majú spoločný len súvisiace triedy (napr. Dedičnosťou), z balíčka v ktorom je hlavný program potom protected atribúty prístupné nebudú.

Ak by sme chceli atribúty alebo metódy sprístupniť iba triede samotnej a jej potomkom, neuvedieme pred nich žiadny modifikátor prístupu.

Začiatok triedy Uzivatel by teda vyzeral takto:

class Uzivatel {
    protected String jmeno;
    protected String heslo;
    protected int vek;

    ...

Keď si teraz vytvoríme inštanciu užívateľa a administrátora, obaja budú mať napr. Atribút jmeno a metódu prihlasit (). Java triedu Uzivatel zdedí a doplní nám automaticky všetky jej atribúty.

Výhody dedenie sú jasné, nemusíme opisovať obom triedam tie isté atribúty, ale stačí dopísať len to, v čom sa líšia. Zvyšok sa zdedí. Prínos je obrovský, môžeme rozširovať existujúce komponenty o nové metódy a tým je znovu využívať. Nemusíme písať hŕbu redundantného (duplikovaného) kódu. A hlavne - keď zmeníme jediný atribút v materskej triede, automaticky sa táto zmena všade zdedí. Nedôjde teda k tomu, že by sme to museli meniť ručne u 20tich tried a niekde na to zabudli a spôsobili chybu. Sme ľudia a chybovať budeme vždy, musíme teda používať také programátorské postupy, aby sme mali možnosť chybovať čo najmenej.

O materskej triede sa niekedy hovorí ako o predkovi (tu Uzivatel) ao triede, ktorá z nej dedí, ako o potomkovi (tu Administrator). Potomok môže pridávať nové metódy alebo si prispôsobovať metódy z materskej triedy (viď ďalej). Môžete sa stretnúť aj s pojmami nadtřída a podtrieda.

Ďalšou možnosťou, ako objektový model navrhnúť, by bolo zaviesť materskú triedu Uzivatel, ktorá by slúžila len k dedenie. Z Uzivatel by potom totiž dedili ošetrovateľ az neho Administrator. To by sa však oplatilo pri väčšom počte typov používateľov. V takomto prípade hovoríme o hierarchii tried, budeme sa tým zaoberať ku koncu tejto sekcie. Náš príklad bol jednoduchý a preto nám stačili iba 2 triedy. Existujú tzv. Návrhové vzory, ktoré obsahujú osvedčená schémy objektových štruktúr pre známe prípady použitia. Záujemcovia je nájdu popísané v sekcii Návrhové vzory, je to však už pokročilejšie problematika a tiež veľmi zaujímavá. V objektovom modelovania sa dedičnosť znázorňuje graficky ako prázdna šípka smerujúca k predkovi. V našom prípade by grafická notácie vyzerala takto:

Dedičnosť objektov – grafická notácie

Dátový typ pri dedičnosti

Obrovskou výhodou dedičnosti je, že keď si vytvoríme premennú s dátovým typom materskej triedy, môžeme do nej bez problémov ukladať aj jej potomkov. Je to dané tým, že potomok obsahuje všetko, čo obsahuje materská trieda, spĺňa teda "požiadavky" (presnejšie obsahuje rozhranie) dátového typu. A k tomu má oproti materskej triede niečo navyše. Môžeme si teda urobiť pole typu Uzivatel a v ňom mať ako užívateľa, tak administrátorov. S premennou to teda funguje takto:

Uzivatel u = new Uzivatel("Jan Novák", 33);
Administrator a = new Administrator("Josef Nový", 25);
// Nyní do uživatele uložíme administrátora:
u = a;
// Vše je v pořádku, protože uživatel je předek
// Zkusíme to opačně a dostaneme chybu:
a = u;

V Jave je veľa konštrukcií, ako operovať s typmi inštanciou pri dedičnosti. Podrobne sa na ne pozrieme počas seriálu, teraz si ukážme len to, ako môžeme overiť typ inštancie v premennej:

Uzivatel u = new Administrator("Josef Nový", 25);
if (u instanceof Administrator) {
    System.out.println("Je to administrátor");
} else {
    System.out.println("Je to uživatel");
}

Pomocou operátora instanceof sa môžeme spýtať, či je objekt daného typu. Kód vyššie otestuje, či je v premennej u užívateľ alebo jeho potomok administrátor.

Jazyky, ktoré dedičnosť podporujú, buď vie dedičnosť jednoduchú, kde trieda dedí len z jednej triedy, alebo viacnásobnú, kde trieda dedí hneď z niekoľkých tried naraz. Viacnásobná dedičnosť sa v praxi príliš neosvedčila, časom si povieme prečo a ukážeme si aj ako ju obísť. Java podporuje len jednoduchú dedičnosť, s viacnásobnou dedičnosťou sa môžete stretnúť napr. V C ++.

Polymorfizmus

Nenechajte sa vystrašiť príšerným názvom tejto techniky, pretože je v jadre veľmi jednoduchá. Polymorfizmus umožňuje používať jednotné rozhranie pre prácu s rôznymi typmi objektov. Majme napríklad veľa objektov, ktoré reprezentujú nejaké geometrické útvary (kruh, štvorec, trojuholník). Bolo by určite prínosné a prehľadné, keby sme s nimi mohli komunikovať jednotne, hoci sa líšia. Môžeme zaviesť triedu GeometrickyUtvar, ktorá by obsahovala atribút farba a metódu vykresli. Všetky geometrické tvary by potom dedili z tejto triedy jej interface (rozhranie). Objekty kruh a štvorec sa ale iste vykresľujú inak. Polymorfizmus nám umožňuje prepísať si metódu vykresli pri každej podtriedy tak, aby robila, čo chceme. Rozhranie tak zostane zachované a my nebudeme musieť premýšľať, ako sa to u onoho objekte volá.

Polymorfizmus býva často vysvetľovaný na obrázku so zvieratami, ktoré majú všetky v rozhraní metódu speak (), ale každé si ju vykonáva po svojom.

polymorfizmus

Podstatou polymorfizmu je teda metóda alebo metódy, ktoré majú všetci potomkovia definované s rovnakou hlavičkou, ale iným telom. Polymorfizmus si spolu s dedičnosťou vyskúšame v nasledujúcej lekcii, Aréna s mágom (dedičnosť a polymorfizmus) , na bojovníkoch v našej aréne. Pridáme mága, ktorý si bude metódu útočí () vykonávať po svojom pomocou many, ale inak zdedí správanie a atribúty bojovníka. Zvonku teda vôbec nespoznáme, že to nie je bojovník, pretože bude mať rovnaké rozhranie. Bude to zábava :)


 

 

Článok pre vás napísal David Čápka
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sa informačné technológie naučil na Unicorn College - prestížnej súkromnej vysokej škole IT a ekonómie.
Predchádzajúci článok
Java - Aréna s bojovníkmi
Všetky články v sekcii
Objektovo orientované programovanie v Jave
Miniatúra
Nasledujúci článok
Aréna s mágom (dedičnosť a polymorfizmus)
Aktivity (1)

 

 

Komentáre

Avatar
Vít Pelc
Člen
Avatar
Vít Pelc:1.2.2017 12:43

Přesně, jak říkáš. :)

 
Odpovedať
1.2.2017 12:43
Avatar
Semjacko
Člen
Avatar
Semjacko:27.2.2017 1:14

Pekne napísané len nerozumiem jednej veci. Ak máme premennú u typu Uzivatel (materská trieda) a premennú a typu Administrator (potomok) a do premennej u uložíme a (u = a), tak u je teraz typu Administrator. Prečo teda nemá nové metody, ktoré obsahuje trieda Administrator?

 
Odpovedať
27.2.2017 1:14
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovedá na Semjacko
David Čápka:27.2.2017 9:19

Ona je má, ale typ je nedovoluje volat. Dále se dozvíš jak to řešit :)

Odpovedať
27.2.2017 9:19
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Semjacko
Člen
Avatar
Odpovedá na David Čápka
Semjacko:27.2.2017 12:51

Ďakujem za odpoveď :)

 
Odpovedať
27.2.2017 12:51
Avatar
Tomáš Kala
Člen
Avatar
Tomáš Kala:22.5.2017 15:36

Proč se dědí i tel. číslo? Vždyť to nemají stejné, ne?

 
Odpovedať
22.5.2017 15:36
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Mirek Slouka
Člen
Avatar
Odpovedá na Tomáš Kala
Mirek Slouka:22.5.2017 15:48

Telefonní číslo nedědí, obsahuje ho jen poděděná třída Administrator :)

Editované 22.5.2017 15:51
Odpovedať
22.5.2017 15:48
I can explain it to you, but I can't understand it for you.
Avatar
pocitac770
Redaktor
Avatar
Odpovedá na Tomáš Kala
pocitac770:22.5.2017 17:23

Všechny atributy, co jsou ve třídách (v předkovi i potomkovi) jsou pouhými "schránkami", do kterých si konkrétní údaje teprve při vytvoření/práci s instancí doplníme, takto mi pouze říkáme, že každý administrátor bude Uživatel, který má ale kromě jména, hesla a věku i telefonní číslo

 
Odpovedať
22.5.2017 17:23
Avatar
Jakub Holeček:7.3.2019 17:14

Ahojte
Mám dotaz ohledně příkazu instanceof.
Je možné ověřit typ instance podle jména?
např.: "

if("Josef Nový" instanceof Administrator){
}

Asi je to hloupý dotaz, ale s programováním teprve začínám a tohle by se mi dost hodilo.

 
Odpovedať
7.3.2019 17:14
Avatar
pocitac770
Redaktor
Avatar
Odpovedá na Jakub Holeček
pocitac770:7.3.2019 20:12

"Josef Nový" je hodnota typu String, protože co je v uvozovkách, to je String. Když takto používáš nějaké operátory, metody atp, tak vždy musíš uvézt tu konkrétní proměnnou, protože co je pro počítač "Josef Nový"? Pouze kus textu, nic víc. Pokud chceš vyhledat někoho toho jména a zjistit, zda je administrátor, tak to tak udělej. Pravděpodobně je budeš mít uložené v nějaké kolekci uživatelů, tak v ní vyhledej podle jména, a nalezeného uživatele zkus pomocí instanceof prozkoumat

 
Odpovedať
7.3.2019 20:12
Avatar
Odpovedá na pocitac770
Jakub Holeček:7.3.2019 21:22

Tak nějak jsem tušil, že to nebude tak jednoduché.
Zkusím si s tím trochu víc pohrát.
Každopádně díky za odpověď.

 
Odpovedať
7.3.2019 21:22
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!