9. diel - Dedičnosť a polymorfizmus v JavaScripte
V minulej lekcii, Dokončenie objektového diáre v JavaScripte , sme dokončili náš objektový diár. Dnes sa v JavaScript tutoriálu pozrieme na dedičnosť a polymorfizmus.
Dedičnosť
Dedičnosť je jedna zo základných techník OOP a slúži k tvoreniu
nových dátových štruktúr na základe starých. Poďme si to ukázať na
príklade. Vytvoríme si všeobecnú triedu Clovek, ktoré
priradíme vlastnosti meno a vek a ešte metódu na predstavenie:
class Clovek { constructor(jmeno, vek) { this.jmeno = jmeno; this.vek = vek; } predstavSe() { return `Jmenuji se ${this.jmeno} a je mi ${this.vek}.`; } }
Kód by vás nemal ničím prekvapiť.
Rozšírenie triedy
Povedzme, že si s touto triedou v aplikácii chvíli vystačíme. Čo keď potom ale potrebujeme ľudí, ktorí budú mať nejaké vlastnosti navyše? Napr. taký programátor je tiež človek s menom, vekom a schopnosťou sa predstaviť, ale navyše by mal programovací jazyk, v ktorom programuje.
Naivné riešenie
Možno by vás napadlo vytvoriť triedu Programator,
skopírovať do nej kód z triedy Clovek a pridať len navyše
vlastnosť jazyk a napr. Tiež metódu
programuj():
class Programator { constructor(jmeno, vek, jazyk) { this.jmeno = jmeno; this.vek = vek; this.jazyk = jazyk; } predstavSe() { return `Jmenuji se ${this.jmeno} a je mi ${this.vek}.`; } programuj() { return `Programuji v ${this.jazyk}...`; } }
Toto riešenie je síce funkčný, ale porušuje jednu z najzákladnejších
dobrých praktík všetkých programátorov - Princíp DRY (Do not Repeat
Yourself, teda neopakujte sa). Predstavte si, že sa v budúcnosti rozhodnete
triedu Clovek upraviť a zabudnete, že je rozkopírovanie do
niekoľkých ďalších súborov. Takéto chyby sa potom zle hľadajú a
samozrejme spôsobí znefunkčnenie vašej aplikácie. Takto teda určite nie

Riešenie pomocou dedičnosti
Novú triedu Programator naozaj vytvoríme, ale z triedy
Clovek ju oddědíme. V JavaScriptu sa pre dedenie
používa v definícii novej triedy kľúčové slovo
extends, takto:
class Potomek extends Predek
Konštruktory a dedičnosť
Je tu však malý háčik. Akonáhle potrebujeme v triede potomka
konštruktor, musíme v ňom najprv zavolať konštruktor predka pomocou funkcie
super(), prípadne mu odovzdať potrebné parametre. Toto
volanie musíme vykonať pred použitím kľúčového slova this.
Ono je to aj logické, konštruktor objekt pripravuje na použitie a ak má
predok nejaký konštruktor, potomok by ho mal vo svojom konstruktoru zavolať,
aby všetko Inicializoval. Konštruktor predka musíme zavolať v konstruktoru
potomka aj v prípade, keby predok nemal definovaný svoj vlastný konštruktor
(aj v tomto prípade totiž konštruktor má, len sa mu vygeneroval
automaticky).
Poďme teda od našej triedy Clovek oddědit novú triedu,
Programator:
class Programator extends Clovek { constructor(jmeno, vek, jazyk) { super(jmeno, vek); this.jazyk = jazyk; } programuj() { return `Programuji v ${this.jazyk}...`; } }
Ako vidíme, máme tu konštruktor s tromi parametrami, z čoho dva
odovzdávame pri zavolaní super() konstruktoru triedy
Clovek, tj. Meno a vek. Ďalej tu máme už spomínanou vlastnosť
jazyk, ktorú tu vytvoríme v konstruktoru pre programátora a
priradíme do nej hodnotu z rovnomenného parametra. Trieda programátor má
teda teraz tri vlastnosti: jmeno, vek a
jazyk a dve metódy - odděděnou predstavSe() a
programuj().
Teraz si v obsluhe vytvoríme inštanciu triedy Programator a
vyskúšame si zavolať obe metódy:
const programator = new Programator("Šimon", 19, "JS"); document.write(` ${programator.predstavSe()}<br> ${programator.programuj()}<br> `);
Teraz sa môžeme pozrieť na výsledok:
Výhody dedičnosti
Výhody dedenie sú jasné, nemusíme opisovať obom triedam tie isté vlastnosti, 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.
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. JavaScript podporuje len jednoduchú dedičnosť, s viacnásobnou dedičnosťou sa môžete stretnúť napr. V C ++. Potomok samozrejme môže mať ďalšieho potomka a tak ďalej.
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 barva
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:

Podstatou polymorfizmu je teda metóda alebo metódy, ktoré majú všetci potomkovia definované s rovnakou hlavičkou, ale iným telom. Vyskúšajme si to na našich ľuďoch.
Predstavenie sa
Človek má definovanú metódu predstavSe(), ktorá pozdravia
týmto spôsobom:
Jmenuji se Marek a je mi 26.
Prepísanie metódy
Teraz aplikujeme polymorfizmus tak, že v triede Programator
metódu predstavSe() z predka upravíme. Prepísanie metódy v
JavaScripte je jednoduché - stačí ju znovu definovať. Naučme teda
programátora predstavovať sa nejakým programátorským spôsobom, napr. Že
použije pozdrav "Hello world!":
class Programator extends Clovek { constructor(jmeno, vek, jazyk) { super(jmeno, vek); this.jazyk = jazyk; } programuj() { return `Programuji v ${this.jazyk}...`; } predstavSe() { return `Hello world! Jmenuji se ${this.jmeno} a je mi ${this.vek}.`; } }
výsledok:
Ak metódu predstavSe() zavoláte na inštanciu triedy
Clovek, vypíše pôvodný text pozdravu. Môžete si to skúsiť
Získali sme teda zhodné
rozhrania a inú funkcionalitu podľa konkrétneho objektu.
Vylepšenia
Všimnite si, že sme použili základné predstavenie z triedy
Clovek, len sme pred neho pridali text "Hello world!". Naše
riešenie vyššie nie je ideálny, pre viac typov ľudí by sme museli stále
kopírovať do každej triedy ten istý predvolený pozdrav a pred neho ešte
len dávať novú hlášku. A už vieme, že podľa DRY je akékoľvek
kopírovanie rovnakého kódu zle.
Základné predstavenie môže vracať metóda predstavSe()
triedy Clovek a my ju môžeme zavolať z potomkov rovnako ako
predtým konštruktor človeka pomocou kľúčového slova super.
Jej výstup potom jednoducho pridáme k textovému reťazcu, ktorý sa bude
vracať:
class Programator extends Clovek { constructor(jmeno, vek, jazyk) { super(jmeno, vek); this.jazyk = jazyk; } programuj() { return `Programuji v ${this.jazyk}...`; } predstavSe() { return `Hello world! ${super.predstavSe()}`; } }
Skúsme si vytvoriť v obsluhe inštanciu triedy človek a zavolajte metódu
predstavSe(), nech vidíme rozdiel:
const programator = new Programator("Šimon", 19, "JS"); document.write(` ${programator.predstavSe()}<br> ${programator.programuj()}<br> `); const clovek = new Clovek("Marek", 26); document.write(clovek.predstavSe());
Výpis bude vyzerať takto:
Tak to je pre dnešok všetko
Dole sú opäť k dispozícii zdrojové kódy na stiahnutie.
Nabudúce, v lekcii Vlastnosti objektov v JavaScripte , sa pozrieme na vlastnosti v JavaScripte.
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é 178x (3.08 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript
