7. díl - Dědičnost a polymorfismus

Java Objektově orientované programování Dědičnost a polymorfismus

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulém tutoriálu o Javě jsme dokončili naši arénu, simulující zápas dvou bojovníků. Dnes si opět rozšíříme znalosti o objektově orientovaném programování. V úvodním dílu do OOP jsme si říkali, že OOP stojí na třech základních pilířích: zapouzdření, dědičnosti a polymorfismu. Zapouzdření a používání modifikátoru private nám je již dobře známé. Dnes se podíváme na zbylé dva pilíře.

Dědičnost

Dědičnost je jedna ze základních vlastností OOP a slouží k tvoření nových datových struktur na základě starých. Vysvětleme si to na jednoduchém příkladu:

Budeme programovat informační systém. To je docela reálný příklad, abychom si však učení zpříjemnili, bude to informační systém pro správu zvířat v ZOO :) Náš systém budou používat dva typy uživatelů: uživatel a administrátor. Uživatel je běžný ošetřovatel zvířat, který bude moci upravovat informace o zvířatech, např. jejich váhu nebo rozpětí křídel. Administrátor bude moci také upravovat údaje o zvířatech a navíc zvířata přidávat a mazat z databáze. Z atributů bude mít navíc telefonní číslo, aby ho bylo možné kontaktovat v případě výpadku systému. Bylo by jistě zbytečné a nepřehledné, kdybychom si museli definovat obě třídy úplně celé, protože mnoho vlastností těchto 2 objektů je společných. Uživatel i administrátor budou mít jistě jméno, věk a budou se moci přihlásit a odhlásit. Nadefinujeme si tedy pouze třídu Uzivatel (nepůjde o funkční ukázku, dnes to bude jen teorie, programovat budeme příště):

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

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

        public boolean odhlasit()
        {
                ...
        }

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

        ...
}

Třídu jsem jen naznačil, ale jistě si ji dokážeme dobře představit. Bez znalosti dědičnosti bychom třídu 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 ve třídě spoustu redundantního (duplikovaného) kódu. Jakékoli změny musíme nyní provádět v obou třídách, kód se nám velmi komplikuje. Nyní použijeme dědičnost, definujeme tedy třídu Administrator tak, aby z třídy Uzivatel dědila. Atributy a metody uživatele tedy již nemusíme znovu definovat, Java nám je do třídy sám dodá:

class Administrator extends Uzivatel
{
        private String telefonniCislo;

        public void pridejZvire(Zvire zvire)
        {

        }

        public void vymazZvire(Zvire zvire)
        {

        }

        ...
}

Vidíme, že ke zdědění jsme použili klíčové slovo "extends". V anglické literatuře najdete dědičnost pod slovem inheritance.

V příkladu výše nebudou v potomkovi přístupné privátní atributy, ale pouze atributy a metody s modifikátorem public. Private atributy a metody jsou chápány jako speciální logika konkrétní třídy, která je potomkovi utajena, i když ji vlastně používá, nemůže ji měnit. Abychom dosáhli požadovaného výsledku, použijeme nový modifikátor přístupu protected.

Protected zpřístupní atribut nebo metodu buď libovolným potomkům v jakémkoli balíčku nebo libovolným třídám v tom samém balíčku. Potomek se tedy již k atributu dostane. Jako problém může být, že atribut je zvenčí viditelný, proto se v souboru .java se třídou často používá jiné jméno balíčku, než ve kterém jsou ostatní části programu. Tento nový balíček mají společný jen související třídy (např. dědičností), z balíčku ve kterém je hlavní program potom protected atributy přístupné nebudou.

Začátek třídy Uzivatel by tedy vypadal takto:

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

        ...

Když si nyní vytvoříme instance uživatele a administrátora, oba budou mít např. atribut jmeno a metodu prihlasit(). Java třídu Uzivatel zdědí a doplní nám automaticky všechny její atributy.

Výhody dědění jsou jasné, nemusíme opisovat oběma třídám ty samé atributy, ale stačí dopsat jen to, v čem se liší. Zbytek se podědí. Přínos je obrovský, můžeme rozšiřovat existující komponenty o nové metody a tím je znovu využívat. Nemusíme psát spousty redundantního (duplikovaného) kódu. A hlavně - když změníme jediný atribut v mateřské třídě, automaticky se tato změna všude podědí. Nedojde tedy k tomu, že bychom to museli měnit ručně u 20ti tříd a někde na to zapomněli a způsobili chybu. Jsme lidé a chybovat budeme vždy, musíme tedy používat takové programátorské postupy, abychom měli možností chybovat co nejméně.

O mateřské třídě se někdy hovoří jako o předkovi (zde Uzivatel) a o třídě, která z ní dědí, jako o potomkovi (zde Administrator). Potomek může přidávat nové metody nebo si uzpůsobovat metody z mateřské třídy (viz dále). Můžete se setkat i s pojmy nadtřída a podtřída.

Další možností, jak objektový model navrhnout, by bylo zavést mateřskou třídu Uzivatel, která by sloužila pouze k dědění. Z Uzivatel by potom dědili Osetrovatel a z něj Administrator. To by se však vyplatilo při větším počtu typů uživatelů. V takovém případě hovoříme o hierarchii tříd, budeme se tím zabývat ke konci této sekce. Náš příklad byl jednoduchý a proto nám stačily pouze 2 třídy. Existují tzv. návrhové vzory, které obsahují osvědčená schémata objektových struktur pro známé případy užití. Zájemci je naleznou popsané v sekci Návrhové vzory, je to však již pokročilejší problematika a také velmi zajímavá. V objektovém modelování se dědičnost znázorňuje graficky jako prázdná šipka směřující k předkovi. V našem případě by grafická notace vypadala takto:

Dědičnost objektů – grafická notace

Datový typ při dědičnosti

Obrovskou výhodou dědičnosti je, že když si vytvoříme proměnnou s datovým typem mateřské třídy, můžeme do ni bez problému ukládat i její potomky. Je to dané tím, že potomek obsahuje vše, co obsahuje mateřská třída, splňuje tedy "požadavky" (přesněji obsahuje rozhraní) datového typu. A k tomu má oproti mateřské třídě něco navíc. Můžeme si tedy udělat pole typu Uzivatel a v něm mít jak uživatele, tak administrátory. S proměnnou to tedy 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 Javě je mnoho konstrukcí, jak operovat s typy instancí při dědičnosti. Podrobně se na ně podíváme během seriálu, nyní si ukažme jen to, jak můžeme ověřit typ instance v proměnné:

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");

Pomocí operátoru instanceof se můžeme zeptat, zda je objekt daného typu. Kód výše otestuje, zda je v proměnné u uživatel nebo jeho potomek administrátor.

Jazyky, které dědičnost podporují, buď umí dědičnost jednoduchou, kde třída dědí jen z jedné třídy, nebo vícenásobnou, kde třída dědí hned z několika tříd najednou. Vícenásobná dědičnost se v praxi příliš neosvědčila, časem si řekneme proč a ukážeme si i jak ji obejít. Java podporuje pouze jednoduchou dědičnost, s vícenásobnou dědičností se můžete setkat např. v C++.

Polymorfismus

Nenechte se vystrašit příšerným názvem této techniky, protože je v jádru velmi jednoduchá. Polymorfismus umožňuje používat jednotné rozhraní pro práci s různými typy objektů. Mějme například mnoho objektů, které reprezentují nějaké geometrické útvary (kruh, čtverec, trojúhelník). Bylo by jistě přínosné a přehledné, kdybychom s nimi mohli komunikovat jednotně, ačkoli se liší. Můžeme zavést třídu GeometrickyUtvar, která by obsahovala atribut barva a metodu vykresli. Všechny geometrické tvary by potom dědily z této třídy její interface (rozhraní). Objekty kruh a čtverec se ale jistě vykreslují jinak. Polymorfismus nám umožňuje přepsat si metodu vykresli u každé podtřídy tak, aby dělala, co chceme. Rozhraní tak zůstane zachováno a my nebudeme muset přemýšlet, jak se to u onoho objektu volá.

Polymorfismus bývá často vysvětlován na obrázku se zvířaty, která mají všechna v rozhraní metodu speak(), ale každé si ji vykonává po svém.

Polymorfismus

Podstatou polymorfismu je tedy metoda nebo metody, které mají všichni potomci definované se stejnou hlavičkou, ale jiným tělem. Polymorfismus si spolu s dědičností vyzkoušíme příště na bojovnících v naší aréně. Přidáme mága, který si bude metodu utoc() vykonávat po svém pomocí many, ale jinak zdědí chování a atributy bojovníka. Zvenčí tedy vůbec nepoznáme, že to není bojovník, protože bude mít stejné rozhraní. Bude to zábava :)


 

  Aktivity (2)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (17 hlasů) :
4.764714.764714.764714.764714.76471


 



 

 

Komentáře
Zobrazit starší komentáře (14)

Avatar
Ondřej Burda:

Parádně sepsaný článek o dědičnosti a polymorfismu. David Čápka zachraňuje studenty i samouky :)

Odpovědět 8.12.2016 19:23
Escape the ordinary
Avatar
Thoragnar Vikernes:

Tak jestli je to střední škola, tak ty jsou úplně k h :D

 
Odpovědět 27.12.2016 11:34
Avatar
Vít Pelc
Člen
Avatar
Odpovídá na Thoragnar Vikernes
Vít Pelc:

To teda :D. V prváku berem Visual Basic, druhým ročníkem nás provází C# a ve třetím ročníku Java. Bohužel, nejdál jsme se ve všech případech dostali k OOP, a to metody a jejich parametry.

 
Odpovědět  ±0 29.12.2016 15:39
Avatar
Odpovídá na Vít Pelc
Thoragnar Vikernes:

Můj kamarád (v takovém smyslu, že se skoro vůbec nevidíme, ale to jaksi nehraje roli) chodí kamsi pod Olomouc na střední, prej že bude programátor. To, co se tam naučil za dva roky je směšné. Ptal jsem se ho aspoň na objektovou kalkulačku a tu by prý udělal, ale musel by u toho hodně hledat. Samozřejmě to není jeho chyba :D. To, co se tam naučíš se dokážeš naučit sám mnohem rychleji a nebudeš to mít zafixovaný, že je to povinnost se učit. Teď si nejsem jistý, zda je gympl lepší, mě třeba vůbec nezajímá každej potentovanej hlavonožec v biologii, elektrolýza všeho možnýho v chemii, kdo koho proklel v dějepise, ale musím se to učit. Podle toho taky vypadají mé známky, no. Bohužel staré zavedené normy platí. Taky mě dostávají kroužky programování, které jsou úplně k ničemu a jenom děckám navodí pocit, že jsou hekři. Kdybych si měl vybrat, tak bych šel možná na grafiku a mezitím samostudoval programován. Jak už jsem říkal, na programátorský škole by to byla povinnost a doma se to naučíš rychleji. Jako když momentálně studuju Norštinu, i když je Němčina užitečnější. Tu se ale učím povinně a jedem podle školskýho tempa a nerad bych, abych se učil podle jiného "algoritmu" (první tohle a tohle), než ve škole. A grafika se dá přece úžasně využít! I když se dá taky vlastně naučit samostudiem. Co to tu plácám, tahle dimenze není pro mě :D. Snad chápeš.

 
Odpovědět  +1 31.12.2016 13:21
Avatar
Odpovídá na Thoragnar Vikernes
Thoragnar Vikernes:

Chybí mi tam pár dodatečných závorek a je tam i někde pravopisná chyba, ale stránka vypisuje chybu, a že nemám oprávnění si upravit vlastní komentář, rip. To s tím učením jako povinnost bude až na výšce, ale to je úplně jiná kapitola. Asi nejdůležitější, studente-vrstevníku. A gl na škole.

 
Odpovědět  +1 31.12.2016 13:28
Avatar
Vít Pelc
Člen
Avatar
Odpovídá na Thoragnar Vikernes
Vít Pelc:

Máš pravdu, ve škole se bere tolik zbytečných věcí dopodrobna, ale to podstatné, co člověka baví, se probere jen tak napovrch. Já jsem si třeba získal ve škole v předmětu Java náskok před ostatními jen díky toho, že jsem se doma učil tutoriály tady na webu. Jinak bych šel jako ostatní spolužáci podle (jak ty říkáš) "školního tempa".

 
Odpovědět  +1 11. ledna 22:37
Avatar
Abe
Člen
Avatar
Odpovídá na Vít Pelc
Abe:

Jestli ti to přijde zlé, od nás bys asi odešel. U nás prvák nic, ve druháku kreslíme vývojáky, teď jsem ve třeťáku a programujeme v C. Za 1. pololetí jsme urazili už opravdu dlouhou cestu (ne, fakt ne) - známe pouze číselné datové typy (něco jako char nebo boolean asi není potřeba), umíme if ... else a nedávno jsme začali cykly while a do while. A to nehodnotím naše půlroční učení se html, kdy o css nebyla jediná zmínka a závěrečná práce měl být web dělaný pomocí tabulky.
Buď rád za to, co vás na škole učí. Jistě ani to nestačí, ale jinde je to ještě mnohem chudší.
PS: Jméno školy radši nezmiňuji :-D...

 
Odpovědět 29. ledna 0:03
Avatar
Vít Pelc
Člen
Avatar
Odpovídá na Abe
Vít Pelc:

Tak to musí být hrozný pocit, když takhle brzdí studenty. Je to škoda, když se někdo chce vzdělávat a rozvíjet podle svého tempa, ale škola mu v tom nedává možnost. Bohužel takto je ale náš systém nastavený, nedá se nic dělat. :/ Aspoň že existuje něco jako internet a potřebné znalosti a zkušenosti můžeme dohledat právě tady. :-)

 
Odpovědět 29. ledna 22:00
Avatar
Abe
Člen
Avatar
Odpovídá na Vít Pelc
Abe:

Jo, plně souhlasím. Já jsem si tehdy, když jsem na tu školu dával přihlášku, myslel, že do světa počítačů, hlavně teda co se týče tvorby programů, mě ta škola uvede dostatečně. Spletl jsem se.
Ale tak hlavně že máme ten internet... A hlavně ten náš itnetwork O:-) Díky němu si můžu jet svým tempem a to mi přece jen vyhovuje :-)

 
Odpovědět  +1 29. ledna 23:32
Avatar
Vít Pelc
Člen
Avatar
Vít Pelc:

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

 
Odpovědět 1. února 12:43
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 24. Zobrazit vše