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

Ostatní jazyky Visual Basic .NET Objektově orientované programování Dědičnost a polymorfismus

V minulém tutoriálu o Visual Basic .NET 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 jmeno As String
        Private heslo As String
        Private vek As Integer

        Public Function Prihlasit(heslo As String) As Boolean
                ' ...
        End Function

        Public Function Odhlasit() As Boolean
                ' ...
        End Function

        Public Sub NastavVahu(zvire As Zvire)
                ' ...
        End Sub

        ' ...

End Class

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 jmeno As String
        Private heslo As String
        Private vek As Integer
        Private telefonniCislo As String

        Public Function Prihlasit(heslo As String) As Boolean
                ' ...
        End Function

        Public Function Odhlasit() As Boolean
                ' ...
        End Function

        Public Sub NastavVahu(zvire As Zvire)
                ' ...
        End Sub

        Public Sub PridejZvire(zvire As Zvire)

        End Sub

        Public Sub VymazZvire(zvire As Zvire)

        End Sub

        ' ...

End Class

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, VB.NET nám je do třídy sám dodá:

Class Administrator
        Inherits Uzivatel
        Private telefonniCislo As String

        Public Sub PridejZvire(zvire As Zvire)

        End Sub

        Public Sub VymazZvire(zvire As Zvire)

        End Sub

        ' ...

End Class

Vidíme, že ke zdědění jsme použili klíčové slovo Inherits. 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, který funguje stejně, jako Private, ale dovoluje tyto atributy dědit. Začátek třídy Uzivatel by tedy vypadal takto:

Class Uzivatel
        Protected jmeno As String
        Protected heslo As String
        Protected vek As Integer

        ' ...

Když si nyní vytvoříme instance uživatele a administrátora, oba budou mít např. atribut jmeno a metodu Prihlasit(). VB.NET 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:

Dim u As New Uzivatel("Jan Novák", 33)
Dim a As 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

Ve VB.NET 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é:

Dim u As Uzivatel = New Administrator("Josef Nový", 25)
If TypeOf u Is Administrator Then
        Console.WriteLine("Je to administrátor")
Else
        Console.WriteLine("Je to uživatel")
End If

Pomocí operátoru TypeOf a Is 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. VB.NET 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 Michal Žůrek (misaz)
Avatar
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.

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


 



 

 

Komentáře

Avatar
Jaroslav Trojan:

Velice pěkně napsáno, škoda jen, že jsem s tím nezačal dříve. Mohl jsem si ušetřit hodně práce.
Děkuji moc, Michale!

 
Odpovědět 28. června 9:59
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 1 zpráv z 1.