Dědičnost

  • V realitě často vidíme, že objektové třídy jsou podtřídami, speciálními případy jiných:

    • všechny objekty podtřídy jsou zároveň objekty nadtřídy, např. každý objekt typu (třídy) DogKeeper je současně typu Person nebo

    • např. každý objekt typu (třídy) Dog je současně typu Pet

  • Někdy to chce realitu trochu zjednodušit, např. zde předpokládat, že v našem výseku reality neexistují psi "nedomácí".

Podtřída

  • Podtřída (říká se též potomek, dceřinná třída, subclass) je tedy specializací, zjemněním své nadtřídy (předka),

  • přebírá její vlastnosti,

  • zpravidla přidává další, čímž svou nadtřídu rozšiřuje (extends).

Note

V Javě je každá uživatelem definovaná třída potomkem nějaké jiné — neuvedeme-li předka explicitně, je předkem vestavěná třída Object.

Správné použití

  • Dědičnost je správně použita jen tehdy, když opravdu můžeme říci, že každý objekt podtřídy je současně objektem nadtřídy,

  • např. DogKeeper je současně Person.

  • Pokud to realitě neodpovídá, není dědičnost na místě.

Proč se dědičnost používá

  • Abychom zohlednili konceptuální vztah obecnější vs. speciálnější typ.

  • Abychom se pomocí toho vyhnuli opakování kódu a dosáhli znovupoužití.

  • Většinou by mělo platit oboje, aby mělo smysl dědičnost použít.

Terminologie dědičnosti

  • Nadtřídě (superclass) se také říká "bezprostřední předek", "rodičovská třída"

  • Podtřídě (subclass) se také říká "bezprostřední potomek", "dceřinná třída"

  • Dědění může mít i více "generací", např.

  • PersonEmployeeManager

  • Osoba je rodičovskou třídou zaměstnance, ten je rodičovskou třídou manažera.

  • Přeneseně tedy předkem (nikoli bezprostředním) manažera je člověk.

Jak zapisujeme dědění

  • Klíčovým slovem extends:

    public class Employee extends Person {
       // ... popis vlastností (proměnných, metod...)
       // zaměstnance navíc oproti (obecnému) člověku...
    }

Dědičnost a vlastnosti tříd (1)

Opakování:

  • Jak víme, třídy popisují skupiny objektů podobných vlastností.

  • Třídy mohou mít tyto skupiny vlastností:

    • Metody - procedury/funkce, které pracují (především) s objekty této třídy

    • Atributy - pojmenované datové prvky (hodnoty) uchovávané v každém objektu této třídy

  • Vlastnosti jsou ve třídě "schované", tzv. zapouzdřené (encapsulated)

  • Třída připomíná záznam známý např. z Pascalu (record) nebo z C jako struct.

  • Záznamy však zapouzdřují jen proměnné, nikoli metody.

  • Co v tomto přináší dědičnost?

Dědičnost a vlastnosti tříd (2)

Dědičnost (alespoň v javovém smyslu) znamená, že dceřinná třída (podtřída, potomek):

  1. všechny vlastnosti (metody, atributy) nadtřídy,

  2. některé zděděné vlastnosti v potomkovi může měnit (metody),

  3. případně v potomkovi přidává další vlastnosti (metody, atributy).

Příklad s Account

Cíl: vylepšit třídu Account (demo 05_Account)

  • Zdokonalíme náš příklad s účtem tak, aby si účet "hlídal", kolik se z něj převádí peněz, aby zůstatek nebyl nižší než povolený minimální

  • Realizujeme tedy změnu jedné z vlastností — metody debit — pomocí jejího překrytí (overriding)

  • Zdokonalenou verzi třídy Account nazveme CheckedAccount

Třída Account

public class Account implements Informing {
   private int balance;
   ...
   public boolean debit(int amount) {
      if(amount <= 0) return false;
      balance -= amount;
      return true;
   }
}

Třída CheckedAccount

public class CheckedAccount extends Account {
   private int minimalBalance; // minimální zůstatek přibývá
   public CheckedAccount(Person owner, int minimalBalance, int initialBalance) {
      super(owner, initialBalance);       // udělá původní inicializaci Account
      if(initialBalance < minimalBalance) { // ověří dostatečný poč. zůstatek
         throw new IllegalArgumentException("initialBalance < minimalBalance");
      }
      this.minimalBalance = minimalBalance;
   }
   public boolean debit(int amount) {
      if(getBalance() - amount >= minimalBalance) { // hlídá si min. zůstatek
         return super.debit(amount);   // je-li zachován, odečte z účtu
      } else return false;             // jinak ne
   }
}

Co tam bylo nového

  • Klíčové slovo extends značí, že třída CheckedAccount je potomkem/podtřídou/rozšířením/dceřinnou třídou (subclass) třídy Account.

  • Konstrukce super.metoda(…); značí, že je volána metoda rodičovské třídy/předka/nadtřídy (superclass).

  • Kdyby se to super nepoužilo, zavolala by se metoda debit třídy CheckedAccount a program by se zacyklil!