Na konci předchozí sekce jste řešili úlohu týkající se rozšíření směnárny o možnost platby
poplatků za prodej. Tuto úlohu jste zřejmě řešili tak, že jste prostě upravili text původní třídy,
možná jste ji i přejmenovali a uložili do jiného souboru. Nabízí se ovšem podstatně
elegantnější metoda, která nám umožní na základě již existující třídy definovat třídu novou, a
tou je dědičnost.
Dědičnost umožňuje využít již existující třídy a přidat k ní další proměnné nebo metody,
případně některé metody předefinovat. Právě možnost předefinování metod nám dává do
rukou velmi silný nástroj pro vývoj programů, pomocí něhož jsme schopni vytvářet různé
implementace téže operace v závislosti na objektu, nad kterým je operace vyvolána.
 | Příklad 2.3. Řešený příklad |
|
Definujte odvozenou třídu SmenarnaSPoplatkem reprezentující směnárnu
s poplatky za prodej valut zákazníkovi. Výška poplatku je stanovena procentem
z částky a je stanovena jeho minimální hodnota.
Tato třída SmenarnaSPoplatkem bude odvozena od původní třídy Smenarna -
přibudou instanční proměnné pro minimální poplatek a velikost poplatku
v procentech, změní se konstruktor a metoda prodej bude předefinovaná tak, aby
zahrnula i výpočet poplatku.
class SmenarnaSPoplatkem extends Smenarna {
public SmenarnaSPoplatkem(double kurz,
double pMin, double pProc)
{
super(kurz);
this.pMin = pMin;
this.pProc = pProc;
}
private double pMin;
private double pProc;
public double prodej(double kolik)
{
double castkaBezPoplatku = kolik * this.vratKurz();
double poplatek = castkaBezPoplatku * pProc / 100;
if( poplatek < pMin ) poplatek = pMin;
return castkaBezPoplatku + poplatek;
}
public static void main(String[] args) {
Smenarna smenarna = new SmenarnaSPoplatkem(30.0, 50, 2);
System.out.println("Vykup(10): " + smenarna.vykup(10));
System.out.println("Prodej(100): " + smenarna.prodej(100));
}
}
Třída SmenarnaSPoplatkem je odvozena od třídy Smenarna, jak je uvedeno za
klíčovým slovem extends. Ovšem to neznamená, že by tato třída měla automaticky přístup ke
všem soukromým proměnným a metodám původní třídy. Musí tedy hodnotu aktuálního kurzu
zjišťovat voláním metody vratKurz(); pokud bychom chtěli odvozeným třídám přímý přístup
umožnit, musíme místo klíčového slova private v deklaraci proměnné nebo metody použít
protected.
|
Konstruktor odvozené třídy má kromě inicializace vlastních instančních proměnných ještě za
úkol provést inicializaci spojenou s nadřazenou třídou, tedy zavolat také její konstruktor.
Volání konstruktoru nadřazené třídy se provádí pomocí klíčového slova super a musí být
prvním příkazem těla konstruktoru. V případě, že konstruktor nadřazené třídy nezavoláme,
zařadí se do programu jeho volání automaticky - v tom případě se volá tzv. implicitní
konstruktor, tedy konstruktor bez parametrů.
Ještě si povšimněte toho, že po vytvoření instance třídy SmenarnaSPoplatkem
operátorem new jsme referenci na vytvořený objekt uložili do proměnné typu Smenarna;
takové přiřazení je zcela v pořádku, referenci na odvozenou třídu můžeme kdykoliv použít
v místě, kde se očekává reference na třídu nadřazenou. Přiřazením reference do proměnné,
která ale ukazuje na nadřazenou třídu, však přicházíme o možnost přístupu k proměnným a
metodám, které má odvozená třída navíc (pokud neprovedeme přetypování zpět na původní
typ).
2.3.1. Úlohy k řešení 2.3.
-
Vytvořte třídu SmenarnaSBonusem, která při výkupu valut nad určitou částku nebude
účtovat poplatek.
-
Rozšiřte model jednoduchého objednávkového systému z předchozí kapitoly o faktury a
dodací listy k realizovaným objednávkám. Pro definici základních typů dokladů využijte
dědičnosti.