Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

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:

Tvoja stránka
localhost

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:

Polymorfizmus v JavaScripte - Objektovo orientované programovanie v JavaScriptu

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:

Tvoja stránka
localhost

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:

Tvoja stránka
localhost

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é 152x (1.24 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript

 

Predchádzajúci článok
Dokončenie objektového diáre v JavaScripte
Všetky články v sekcii
Objektovo orientované programovanie v JavaScriptu
Preskočiť článok
(neodporúčame)
Vlastnosti objektov v JavaScripte
Článok pre vás napísal Šimon Raichl
Avatar
Užívateľské hodnotenie:
2 hlasov
Autor se věnuje hlavně tvorbě všemožných věcí v JS
Aktivity