11 Diagram tříd, asociace, dědičnost, abstraktní třídy Studijní cíl Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost diagramům tříd, asociaci, dědičnosti a abstraktním třídám.
Doba nutná k nastudování
2 – 2,5 hodiny
11.1 Diagram tříd V minulém bloku jsme se seznámili s ikonou třídy, která se omezuje svým pohledem pouze na jednu třídu. Nyní se podívám na rozsáhlejší přehled o třídách, který nám umožňuje diagram tříd – viz Obrázek 1. Diagram tříd umožňuje graficky dokumentovat vztah mezi třídami. Jak jsme si již uvedli v kapitole věnující se třídám, tak se program v jazyce Java skládá z celé řady tříd, které mají být nezávislé.
Obrázek 1: Ukázka diagramu tříd
KST/IZAPR - Základy programování
blok 11, strana 1 (8)
Michael Bažant
11.2 Asociace Existuje více asociačních vazeb mezi třídami, my se nyní omezíme se pouze na jednoduchou asociaci. Tento typ vazby používáme v případech, kdy můžeme vyjádřit vazbu mezi třídami slovesem „má“ – viz Obrázek 1, kde jeden ovladač má jeden DVD přehrávač. Orientace hrany mezi těmito třídami představuje tok informací, v tomto případě tedy ovladač posílá informace dvd přehrávači (např. pokyny přehraj, zastav přehrávání apod.). Dalším typům asociačních vazeb (např. agregace, kompozice apod.) bude věnována pozornost v předmětu Objektově orientované programování. V jazyce Java asociační vazbu mezi třídami zapisujeme pomocí referenční proměnné, která je deklarována ve třídě, ze které vychází orientovaná hrana asociace. Příklad: public class Ovladac { public DVDPrehravac dvdPrehravac; public Ovladac() { … } } U asociační hrany jsou k dispozici informace jak o názvu referenční proměnné, tak o jejím přístupovém právu a také o násobnosti. V našem případě se jedná o násobnost 1:1, což znamená, že jeden ovladač ovládá jeden dvd přehrávač. Obecně lze říci, že je možné používat libovolné násobnosti, které se zapisují k asociační hraně, např. 1:2, 1:m, m:n apod.
11.3 Dědičnost Dědičnost používáme v případech, kdy dvě nebo více tříd mají společné prvky a dědičnost může pomoci v odstranění duplicit ve zdrojovém kódu. Hned na úvod výkladu dědičnosti je ale nutné upozornit na to, že je velkou chybou používat dědičnost pouze na základě úsudku o tom, že nějaké třídy mají společné prvky a tak lze použít dědičnost pro odstranění duplicit. Můžeme se podívat na jednoduchý příklad, ve kterém figurují geometrické tvary, které chceme vykreslit na nějaký formulář.
KST/IZAPR - Základy programování
blok 11, strana 2 (8)
Michael Bažant
Obrázek 2: Geometrické tvary
Na první pohled je zřejmé, že tyto tvary disponují prvky, které jsou pro všechny tyto tvary společné. Mohli bychom tedy založit třídu Tvar, která by obsahovala společné prvky pro tyto třídy. Pro rozhodnutí o tom, zda použít mezi třídami vazbu tyto dědičnost je rozhodující, zda získáme kladnou odpověď na otázku – je obdélník tvarem? Pokud je odpověď kladná, je možné použít mezi třídami dědičnost – viz Obrázek 3, kdy třída, která má společné atributy se nazývá předek a třídy, které dědí, se nazývají potomci. V diagramu tříd je tato vazba znázorněna orientovanými hranami, jejichž orientace vede k předkovi. Orientované hrany u asociace a dědičnosti se liší svým tvarem – viz Obrázek 1 a Obrázek 3.
Obrázek 3: Dědičnost mezi třídami
V jazyce Java zapisujeme dědičnost pomocí klíčového slova extends ve třídě potomka (daná třída tedy rozšiřuje třídu předka) – viz Obrázek 4.
KST/IZAPR - Základy programování
blok 11, strana 3 (8)
Michael Bažant
Obrázek 4: Zápis dědičnosti v jazyce Java
V jazyce Java (na rozdíl od jiných jazyků) není povolena vícenásobná dědičnost, tzn., že jedna třída může mít maximálně jednoho předka. Jeden předek samozřejmě může mít i více potomků – viz Obrázek 3. V terminologii programování hovoříme také o tom, že předek je vždy třídou, která je více abstraktní než potomek a potomek je třídou, která je více konkrétní než předek. Každá třída má svého předka, i pokud žádného nedeklarujeme explicitně – viz Obrázek 5.
Obrázek 5: Implicitní dědičnost
Každý potomek v sobě nese informace, kterými disponuje předek a dále k těmto informacím přidává své vlastní informace – viz Obrázek 6.
Obrázek 6: Příklad dědičnosti
KST/IZAPR - Základy programování
blok 11, strana 4 (8)
Michael Bažant
Třída Object je základní třídou, která je předkem pro všechny třídy, které explicitně nedeklarují předka jiného. Třída java.lang.Object disponuje několika veřejnými metodami, se kterými je dobré se seznámit, např. metoda toString() – vrací textovou reprezentaci objektu metoda equals(Object obj) – vrací, zda se jedná o objekt, který je ekvivalentní k jinému objektu metoda hashCode() – vrací hash kód objektu metoda clone() – vytváří a vrací kopii objektu
11.3.1 Dědičnost a konstruktory Potomek vždy rozšiřuje svého předka, a proto je vždy nutné vytvořit objekt předka ještě před tím, než je vytvořen objekt potomka. Z tohoto důvodu je v konstruktoru potomka vždy nejdříve volán konstruktor předka (musí na prvním řádku konstruktoru potomka) a to buď implicitně (pokud jej nevoláme explicitně) nebo máme možnost jej volat explicitně. Implicitně je vždy volán bezparametrický konstruktor předka, a pokud tento není k dispozici, je nutné volat parametrický konstruktor předka explicitně pomocí klíčového slova super.
Obrázek 7: Implicitní volání konstruktoru předka
11.4 Dědičnost – přístupová práva U dědičnosti je možné využívat modifikátor protected. Následující tabulka rekapituluje přístupová práva, která jsme si již představili v předchozím bloku a také přehledně znázorňuje přístupová práva od nejvíce restriktivního private až po nejméně striktní public.
KST/IZAPR - Základy programování
blok 11, strana 5 (8)
Michael Bažant
Obrázek 8: Přístupová práva
Příklad na přístupová práva v hierarchii dědičnosti a v různých balíčcích (p1, p2) demonstruje následující příklad:
Obrázek 9: Příklad na využití přístupových práv
11.5 Dědičnost – překrývání metod Potom dědí jak atributy, tak metody od svého předka. V potomkovi je možné změnit implementaci metody předka pomocí tzv. překrývání metod (method overriding). Typicky se tato technika využívá např. u metody toString() apod. Metody mohou být překryty pouze tehdy, pokud jsou dostupné, privátní metody nejsou dostupné mimo třídu, kde jsou definovány, a proto nemohou být překryty. V takovém případě se nejedná o překryté metody, ale zcela nezávislé metody. Pakliže se má jednat o překrývání metod, jak je nezbytné, aby byla shoda v názvu metody, v návratovém typu, v seznamu parametrů a přístupová práva nemohou být více restriktivní.
KST/IZAPR - Základy programování
blok 11, strana 6 (8)
Michael Bažant
Pro dokumentaci rozdílu mezi přetěžováním a překrýváním metod slouží následující obrázek – viz
Obrázek 10: Rozdíl mezi překrýváním a přetěžováním metod
11.6 Abstraktní třídy V jazyce Java je možné v deklaraci tříd zapsat, že není možné na základě dané třídy vytvářet objekty. Takovým třídám říkáme abstraktní třídy a používáme u nich modifikátor abstract. V ikoně třídy tuto skutečnost znázorňujeme pomocí využití písma kurzíva – viz Obrázek 11, kde figuruje abstraktní třída Zamestnanec.
Obrázek 11: Abstraktní třída zaměstnanec
KST/IZAPR - Základy programování
blok 11, strana 7 (8)
Michael Bažant
Otázky na procvičení 1. 2. 3. 4. 5.
Jaký je rozdíl mezi přetěžováním a překrýváním metod? Co je to překrývání metod? Co platí z hlediska dědičnosti pro přístupová práva protected? Může mít v jazyce Java potomek více předků? Co je to asociační vazba?
Odkazy a další studijní prameny 1. Java Tutorial - http://docs.oracle.com/javase/tutorial/
KST/IZAPR - Základy programování
blok 11, strana 8 (8)
Michael Bažant