====== Polymorfismus, dědičnost - Geometrické obrazce ======
Polymorfismem rozumíme techniku, kdy očekáváme, že jeden objekt dokáže zastoupit druhý. Tzn. že dokáže odpovědět na nějakou sadu zpráv.
Nechť máme sadu grafických objektů, např. pro plotter. Chceme od každého objektu vědět, kolik na něj spotřebujeme inkoustu, tj. jeho obvod. Ale je nám jedno, co je objekt zač. Nezajímá nás, jestli je to kruh nebo čtverec, chceme od něj jen ten obvod. Takže pošleme zprávu ''obvod'' (zavoláme metodu ''obvod'') a očekáváme, že každý objekt v kolekci reprezentující naši scénu nám odpoví.
Polymorfismus lze v Javě kvůli typové kontrole při překladu realizovat buď pomocí dědičnosti (klíčové slovo **extends**) nebo pomocí interfaců (**implements**).
Dědění používáme, pokud potřebujeme nějakým způsobem vytvořit hierarchii objektů a sdílet společný kód mezi členy hierarchie.
Interfacy slouží jen k definování, že třída, která interface implementuje, má rozumět těm a těm zprávám (implementovat příslušné metody).
Pozor, rozhodně **neplatí**, že dědičnost == polymorfismus. Pokus o prosazení této rovnosti pro vás bude pravděpodobně znamenat nedobrovolný odchod ze zkoušky :-). Dědičnost je jen jeden ze způsobů, jak polymorfismus zařídit v jazyce typu Java.
===== Kruh.java =====
Kruh je potomkem třídy //Utvar2D//. Abychom mohli vytvářet instance, potřebujeme implementovat metody //obvod// a //obsah//.
package omo4;
public class Kruh extends Utvar2D{
int x, y, r;
public Kruh (int x, int y, int r) {
this.x = x;
this.y = y;
this.r = r;
}
public double obvod(){
return 2 * Math.PI * r;
}
public double obsah() {
return Math.PI * r * r;
}
}
===== Obdelnik.java =====
Obdelnik je potomkem třídy //Utvar2D// a zároveň implementuje interface //Hranaty// (hranatý objekt, objekt s hranami) - metoda //nejdelsiHrana//.
package omo4;
public class Obdelnik extends Utvar2D implements Hranaty{
int x1,y1,x2,y2;
public Obdelnik (int x1, int y1, int x2, int y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public double obvod (){
return (Math.abs(x2 - x1) * 2)
+
(Math.abs(y2 - y1) * 2);
}
public double obsah() {
return Math.abs(x2 - x1) * Math.abs(y2 - y1);
}
public double nejdelsiHrana() {
return Math.max(Math.abs(x2 - x1), Math.abs(y2 - y1));
}
}
===== Utvar2D.java =====
Abstraktní třídy, narozdíl od interfaců, mohou mít i metody s definovaným kódem a tak definovat nějaké metody společné pro všechny podtypy. Naši hierarchii rozšíříme o jednu úroveň a dodáme nadřazenou třídu (superclass) //Utvar// (a případně sourozence //Utvar3D//). Teď můžeme potřebovat metodu //jeRovinny//, která by pro všechny 2D útvary (čili potomky //Utvar2D//) vracela true. Pak se jeví vhodné ji vložit přímo do třídy //Utvar2D//.
package omo4;
public abstract class Utvar2D extends Utvar{
public boolean jeRovinny(){
return true;
}
public abstract double obvod();
public abstract double obsah();
}
===== Utvar.java =====
Třída pro všechny útvary. Dal jsem ji sem jen kvůli příkladu na metodu v abstraktní třídě.
package omo4;
public abstract class Utvar {
public abstract boolean jeRovinny();
}
===== Hranaty.java =====
Interface pro všechny útvary s hranami. U nich chceme určovat i délku nejdelší hrany.
package omo4;
public interface Hranaty {
public double nejdelsiHrana();
}
===== Main.java =====
package omo4;
public class Main {
public static double sectiObvody(Utvar2D[] pole){
double soucet = 0;
for (Utvar2D prvek: pole){
soucet += prvek.obvod();
}
return soucet;
}
public static double vratMaxHranu(Hranaty[] pole){
double max = 0;
for (Hranaty prvek: pole){
if (prvek.nejdelsiHrana() > max){
max = prvek.nejdelsiHrana();
}
}
return max;
}
public static void main (String [] args){
Kruh k = new Kruh (0,0,10);
System.out.println(k.obvod());
Obdelnik o = new Obdelnik(0, 0, 10, 20);
System.out.println(o.obvod());
System.out.println(o.jeRovinny());
Utvar2D [] pole = new Utvar2D[2];
pole[0] = k;
pole[1] = o;
System.out.println(sectiObvody(pole));
Hranaty[] pole2 = new Hranaty[2];
pole2[0] = o;
pole2[1] = new Obdelnik(0,0,14,15);
System.out.println(vratMaxHranu(pole2));
}
}