Gyakorlati alapok III.
Öröklődés (inheritance)
Osztályvariációk hangszeres témára
Az egyik tanítványomnak az alábbi feladatot adtam fel:
Határozz meg egy absztrakt Hangszer osztályt és abból származtass
hangszereket, majd ezeket hasonlítsd össze egymással!
Bevallom, a feladat túl általános, ezért kissé nehéz az
osztálykörnyezetekkel ismerkedő tanítvány számára, bár megjegyzem:
ennél több konkrétumot a laikus megrendelő sohasem fog közölni. Ám
egyúttal éppen ebben rejlik sokszínű megoldási lehetősége, hiszen oly
sokféleképpen oldható meg. Először nézzük meg a feladat kibontását elvi
szinten.
1.
Határozz meg egy absztrakt Hangszer osztályt…
Attól függetlenül, hogy a programozó mennyire jártas a hangszerekben vagy
egyéb témákban, kis utánaolvasással tudnia kell a valóság legtöbbször az
ügyfél által kért vagy elvárt szeleteit modellezni. Ha ugyanis erre
képtelen, nem lesz képes az osztályokat az objektumorientált elveknek
megfelelően felépíteni. A mi esetünkben mi lehet a hangszer, mint
absztrakt fogalom 2 legáltalánosabb tulajdonsága? Véleményem szerint a
hangszeranyag és a hangtartomány. Természetesen egy valós projektben,
például egy gitárhangoló programban ilyen szintű absztrakcióra nincs
szükség, de nagyon hasznos, ha gyakorláskor foglalkozunk a legfelső,
„filozófiai”, absztrakciós szinttel is.
2.
...és abból származtass hangszereket…
Van tehát 2 öröklött tulajdonságunk, amelyeket a származtatás során akár
újabb tulajdonságokkal egészíthetünk ki. Ezzel tehát elindult a
specializálódás folyamata.
3.
...majd ezeket hasonlítsd össze egymással.
Ez valójában a tulajdonságok alapszintű egyenlőség-, és
összehasonlítás-vizsgálatát jelenti, amelyet a
Controller osztályként (A
Controller osztály lehetősége című fejezet) használt
Main osztályban külön
equals() függvényekben tehetünk meg (bár akár azokat is külön
osztályba rendezhetjük, amit én most nem tettem meg).
Kezdjük a „klasszikus” megoldással, amely során nincs absztrakt
osztályunk, csakis egy ősosztálynak szánt Gitar
osztály...
public class Gitar {
private String hangszeranyag;
private int hangtartomany;
private int hurszam;
...ezért rájuk kötelező megalkotnunk a getter-setter függvényeket (Get it and set it!
című fejezet)…
public String getHangszeranyag() {
return hangszeranyag;
}
public void setHangszeranyag(String hangszeranyag) {
this.hangszeranyag = hangszeranyag;
}
public int getHangtartomany() {
return hangtartomany;
}
public void setHangtartomany(int hangtartomany) {
this.hangtartomany = hangtartomany;
}
public int getHurszam() {
return hurszam;
}
public void setHurszam(int hurszam) {
this.hurszam = hurszam;
}
...amelyeket az osztály konstruktor függvényében rögtön fel is használunk:
Gitar() {
this.setHangszeranyag("Fa");
this.setHangtartomany(72);
this.setHurszam(6);
}
}
Miért itt? – vetődik fel a jogos kérdés. Nos, véleményem szerint a gitár
most meghatározott, konkrét tulajdonságai nem átmeneti, hanem standard
értékek, ezért akár az osztály konstruktorában, mintegy „elvi” szinten is
beállíthatók. Ez nyilvánvalóan azt fogja okozni, hogy az osztály
példányosításának pillanatában az objektum ezen tulajdonságokkal lesz már
feltöltve. Persze „illékonyabb” bemeneti adatok esetén ezt máshol, esetleg
magától a felhasználótól kell bekérnünk és ez minimum külön osztályt,
talán még külön földrészt is jelent.
Az Ukulele osztály a
Gitar osztályból származtatott, a super()
függvény segítségével mindent örököl (emlékezzünk vissza: deklarálása
nélkül is!) és konkrét tulajdonságainak beállítása azonos a
Gitar osztályban alkalmazottal:
public class Ukulele extends Gitar {
public class Ukulele extends Gitar {
Ukulele() {
this.setHangszeranyag("Fa");
this.setHangtartomany(48);
this.setHurszam(4);
}
}
Az Uzenetek osztály
void típusú metódusai a bemeneti boolean
típusú isValid változók segítségével írja ki
a 2 hangszer tulajdonságainak összehasonlítási eredményeit, például
hangszeranyag esetében...
public class Uzenetek {
void hangszeranyagOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A hangszeranyagok
egyeznek.");
}
else
System.out.println("A hangszeranyagok
NEM egyeznek.");
}
void hangtartomanyOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar
hangtartomanya nagyobb.");
}
else
System.out.println("Az ukulele
hangtartomanya nagyobb.");
}
void hurszamOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hurszama
nagyobb.");
}
else
System.out.println("Az ukulele
hurszama nagyobb.");
}
}
Az objektumok példányosítása és az egész lefuttatása pedig a
main() főmetóduson belül történik (a kódot
néhol lekicsinyítettem, hogy ne kerüljön bele zavaró sortörés):
public class Main {
boolean equalsHangszeranyag(String gitarAnyag, String ukuleleAnyag) {
boolean isValid = false;
if(gitarAnyag.equals(ukuleleAnyag)) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHangtartomany(int gitarHangtartomany, int
ukuleleHangtartomany) {
boolean isValid = false;
if(gitarHangtartomany > ukuleleHangtartomany) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHurszam(int gitarHurszam, int ukuleleHurszam) {
boolean isValid = false;
if(gitarHurszam > gitarHurszam) {
isValid = true;
return isValid;
}
return isValid;
}
public static void main(String[] args)
{
Gitar gitar = new Gitar();
Ukulele ukulele = new Ukulele();
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.getHangszeranyag(), ukulele.getHangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.getHangtartomany(),ukulele.getHangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(),
ukulele.getHurszam()));
}
}
Nézzük meg egyben a futtatható Java-kódot:
Gitar.java
public class Gitar {
private String hangszeranyag;
private int hangtartomany;
private int hurszam;
public String getHangszeranyag() {
return hangszeranyag;
}
public void setHangszeranyag(String hangszeranyag) {
this.hangszeranyag = hangszeranyag;
}
public int getHangtartomany() {
return hangtartomany;
}
public void setHangtartomany(int hangtartomany) {
this.hangtartomany = hangtartomany;
}
public int getHurszam() {
return hurszam;
}
public void setHurszam(int hurszam) {
this.hurszam = hurszam;
}
Gitar() {
this.setHangszeranyag("Fa");
this.setHangtartomany(72);
this.setHurszam(6);
}
}
Ukulele.java
public class Ukulele extends Gitar {
Ukulele() {
this.setHangszeranyag("Fa");
this.setHangtartomany(48);
this.setHurszam(4);
}
}
Uzenetek.java
public class Uzenetek {
void hangszeranyagOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A hangszeranyagok
egyeznek.");
}
else
System.out.println("A hangszeranyagok
NEM egyeznek.");
}
void hangtartomanyOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar
hangtartomanya nagyobb.");
}
else
System.out.println("Az ukulele
hangtartomanya nagyobb.");
}
void hurszamOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hurszama
nagyobb.");
}
else
System.out.println("Az ukulele
hurszama nagyobb.");
}
}
Main.java
public class Main {
boolean equalsHangszeranyag(String gitarAnyag, String ukuleleAnyag) {
boolean isValid = false;
if(gitarAnyag.equals(ukuleleAnyag)) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHangtartomany(int gitarHangtartomany, int
ukuleleHangtartomany) {
boolean isValid = false;
if(gitarHangtartomany > ukuleleHangtartomany) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHurszam(int gitarHurszam, int ukuleleHurszam) {
boolean isValid = false;
if(gitarHurszam > gitarHurszam) {
isValid = true;
return isValid;
}
return isValid;
}
public static void main(String[] args)
{
Gitar gitar = new Gitar();
Ukulele ukulele = new Ukulele();
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.getHangszeranyag(), ukulele.getHangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.getHangtartomany(),ukulele.getHangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(),
ukulele.getHurszam()));
}
}
Végeredmény:
A hangszeranyagok egyeznek.
A gitar hangtartomanya nagyobb.
A gitar hurszama nagyobb.
A 2. osztályvariációban egy teljesen absztrakt Hangszer osztályból
indulunk ki:
public abstract class Hangszer {
protected int hangtartomany;
protected String hangszeranyag;
}
A tulajdonságokat a protected hozzáférés módosítással védjük (A
hozzáférés-módosítók című
fejezet). A Gitar osztályt belőle származtatjuk, egyúttal egy új,
int hurSzam tulajdonsággal egészítjük ki, amelyhez azonnal legeneráljuk a
getter-setter függvényeket, illetve látható, hogy a konkrét
tulajdonságértékeket a már ismertetett alapelvek szerint a konstruktor
függvényben állítjuk be:
public class Gitar extends Hangszer {
protected int hurszam;
public int getHurszam() {
return hurszam;
}
public void setHurszam(int hurszam) {
this.hurszam = hurszam;
}
Gitar() {
super();
this.hangtartomany = 72;
this.hangszeranyag = "Fa";
this.setHurszam(6);
}
}
Az Ukulele osztályt a
Gitar osztályból származtatjuk és konkrét
tulajdonságértékeit szintén a konstruktor függvényben állítjuk be:
public class Ukulele extends Gitar {
Ukulele() {
super();
this.hangszeranyag = "Fa";
this.hangtartomany = 48;
this.setHurszam(4);
}
}
Innen a Main és Uzenetek osztály az 1. variációval azonosak. Nézzük meg a
teljes, futtatható Java-kódot:
Hangszer.java
public abstract class Hangszer {
protected int hangtartomany;
protected String hangszeranyag;
}
Gitar.java
public class Gitar extends Hangszer {
protected int hurszam;
public int getHurszam() {
return hurszam;
}
public void setHurszam(int hurszam) {
this.hurszam = hurszam;
}
Gitar() {
super();
this.hangtartomany = 72;
this.hangszeranyag = "Fa";
this.setHurszam(6);
}
}
Ukulele.java
public class Ukulele extends Gitar {
Ukulele() {
super();
this.hangszeranyag = "Fa";
this.hangtartomany = 48;
this.setHurszam(4);
}
}
Uzenetek.java
public class Uzenetek {
void hangszeranyagOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A hangszeranyagok
egyeznek.");
}
else
System.out.println("A hangszeranyagok
NEM egyeznek.");
}
void hangtartomanyOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar
hangtartomanya nagyobb.");
}
else
System.out.println("Az ukulele
hangtartomanya nagyobb.");
}
void hurszamOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hurszama
nagyobb.");
}
else
System.out.println("Az ukulele
hurszama nagyobb.");
}
}
Main.java
public class Main {
boolean equalsHangszeranyag(String gitarAnyag, String ukuleleAnyag) {
boolean isValid = false;
if(gitarAnyag.equals(ukuleleAnyag)) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHangtartomany(int gitarHangtartomany, int
ukuleleHangtartomany) {
boolean isValid = false;
if(gitarHangtartomany > ukuleleHangtartomany) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHurszam(int gitarHurszam, int ukuleleHurszam) {
boolean isValid = false;
if(gitarHurszam > gitarHurszam) {
isValid = true;
return isValid;
}
return isValid;
}
public static void main(String[] args)
{
Gitar gitar = new Gitar();
Ukulele ukulele = new Ukulele();
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.getHangszeranyag(), ukulele.getHangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.getHangtartomany(),ukulele.getHangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(),
ukulele.getHurszam()));
}
}
Végeredmény:
A hangszeranyagok egyeznek.
A gitar hangtartomanya nagyobb.
A gitar hurszama nagyobb.
A 3. variációban szintén egy absztrakt Hangszer osztályból indulunk ki:
public abstract class Hangszer {
abstract int hangtartomany();
abstract String hangszeranyag();
}
A belőle származtatott Gitar osztályban a deklarált metódusfejeket
kötelező kidolgoznunk, amelyekben ilyen módon meg is adjuk a konkrét
tulajdonságértékeket. Egyúttal kidolgozzuk a hurszam tulajdonságot is,
amelyhez elégséges 1 db getter-függvényt generálnunk, hiszen párjára, a
setter-függvényre a jelen projektben nem lesz szükség:
public class Gitar extends Hangszer {
private int hurszam;
public int getHurszam() {
return 6;
}
public int hangtartomany() {
return 72;
}
public String hangszeranyag() {
return "Fa";
}
}
Az Ukulele osztály a
Gitar osztályból származtatott, de 1 tulajdonságuk
azonos: mindketten fából készültek, ezért a hangszeranyag() metódust nem
kell felülírnunk, a többit azonban igen:
public class Ukulele extends Gitar {
public int getHurszam() {
return 4;
}
public int hangtartomany() {
return 48;
}
}
A Main és Uzenetek osztályok nem változnak, kivéve, hogy bár a
Main
osztályban a függvényneveket át kell írni, a logikai konstrukció azonban
ott sem változik. Nézzük meg a futtatható java-kódot:
Hangszer.java
public abstract class Hangszer {
abstract int hangtartomany();
abstract String hangszeranyag();
}
Gitar.java
public class Gitar extends Hangszer {
private int hurszam;
public int getHurszam() {
return 6;
}
public int hangtartomany() {
return 72;
}
public String hangszeranyag() {
return "Fa";
}
}
public class Ukulele extends Gitar {
public int getHurszam() {
return 4;
}
public int hangtartomany() {
return 48;
}
}
Ukulele.java
public class Ukulele extends Gitar {
public int getHurszam() {
return 4;
}
public int hangtartomany() {
return 48;
}
}
Uzenetek.java
public class Uzenetek {
void hangszeranyagOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A hangszeranyagok egyeznek.");
}
else
System.out.println("A hangszeranyagok NEM egyeznek.");
}
void hangtartomanyOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hangtartomanya nagyobb.");
}
else
System.out.println("Az ukulele hangtartomanya nagyobb.");
}
void hurszamOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hurszama nagyobb.");
}
else
System.out.println("Az ukulele hurszama nagyobb.");
}
}
Main.java
public class Main {
boolean equalsHangszeranyag(String gitarAnyag, String ukuleleAnyag) {
boolean isValid = false;
if(gitarAnyag.equals(ukuleleAnyag) ) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHangtartomany(int gitarHangtartomany, int
ukuleleHangtartomany) {
boolean isValid = false;
if(gitarHangtartomany > ukuleleHangtartomany) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHurszam(int gitarHurszam, int ukuleleHurszam) {
boolean isValid = false;
if(gitarHurszam > gitarHurszam) {
isValid = true;
return isValid;
}
return isValid;
}
public static void main(String[] args) {
Gitar gitar = new Gitar();
Ukulele ukulele = new Ukulele();
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.hangszeranyag(),
ukulele.hangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.hangtartomany(),
ukulele.hangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(),
ukulele.getHurszam()));
}
}
Végeredmény:
A hangszeranyagok egyeznek.
A gitar hangtartomanya nagyobb.
A gitar hurszama nagyobb.
A 4., egyben utolsó variációban pedig visszatérünk az 1., klasszikusnak
mondható
megoldásunkhoz annyi különbséggel, hogy a tulajdonságoknak csakis a
példányosításkor, a main() főprogramban adunk
konkrét értékeket:
public static void main(String[] args) {
Gitar gitar = new Gitar();
gitar.setHangszeranyag("Fa");
gitar.setHangtartomany(72);
gitar.setHurszam(6);
Ukulele ukulele = new Ukulele();
gitar.setHangszeranyag("Fa");
gitar.setHangtartomany(48);
gitar.setHurszam(4);
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.getHangszeranyag(), ukulele.getHangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.getHangtartomany(), ukulele.getHangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(), ukulele.getHurszam()));
}
Ráadásként, mivel az Ukulele osztály az összes tulajdonságot
változtatás-bővítés nélkül örökli, „tupírozni” bár lehetne, ám
deklarációja alapjában véve tökéletesen elégséges az alábbi módon:
public class Ukulele extends Gitar {
}
Nézzük meg a futtatható Java-kódot:
Gitar.java
public class Gitar {
private String hangszeranyag;
private int hangtartomany;
private int hurszam;
public String getHangszeranyag() {
return hangszeranyag;
}
public void setHangszeranyag(String hangszeranyag) {
this.hangszeranyag = hangszeranyag;
}
public int getHangtartomany() {
return hangtartomany;
}
public void setHangtartomany(int hangtartomany) {
this.hangtartomany = hangtartomany;
}
public int getHurszam() {
return hurszam;
}
public void setHurszam(int hurszam) {
this.hurszam = hurszam;
}
}
public class Ukulele extends Gitar {
}
Uzenetek.java
public class Uzenetek {
void hangszeranyagOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A hangszeranyagok egyeznek.");
}
else
System.out.println("A hangszeranyagok NEM egyeznek.");
}
void hangtartomanyOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hangtartomanya nagyobb.");
}
else
System.out.println("Az ukulele hangtartomanya nagyobb.");
}
void hurszamOsszehasonlitas(boolean isValid) {
if(isValid == true) {
System.out.println("A gitar hurszama nagyobb.");
}
else
System.out.println("Az ukulele hurszama nagyobb.");
}
}
Main.java
public class Main {
boolean equalsHangszeranyag(String gitarAnyag, String ukuleleAnyag) {
boolean isValid = false;
if(gitarAnyag.equals(ukuleleAnyag) ) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHangtartomany(int gitarHangtartomany, int
ukuleleHangtartomany) {
boolean isValid = false;
if(gitarHangtartomany > ukuleleHangtartomany) {
isValid = true;
return isValid;
}
return isValid;
}
boolean equalsHurszam(int gitarHurszam, int ukuleleHurszam) {
boolean isValid = false;
if(gitarHurszam > gitarHurszam) {
isValid = true;
return isValid;
}
return isValid;
}
public static void main(String[] args) {
Gitar gitar = new Gitar();
gitar.setHangszeranyag("Fa");
gitar.setHangtartomany(72);
gitar.setHurszam(6);
Ukulele ukulele = new Ukulele();
gitar.setHangszeranyag("Fa");
gitar.setHangtartomany(48);
gitar.setHurszam(4);
Main main = new Main();
Uzenetek uzenet = new Uzenetek();
uzenet.hangszeranyagOsszehasonlitas(main.equalsHangszeranyag(gitar.getHangszeranyag(), ukulele.getHangszeranyag()));
uzenet.hangtartomanyOsszehasonlitas(main.equalsHangtartomany(gitar.getHangtartomany(), ukulele.getHangtartomany()));
uzenet.hurszamOsszehasonlitas(main.equalsHangtartomany(gitar.getHurszam(), ukulele.getHurszam()));
}
Végeredmény:
A hangszeranyagok egyeznek.
A gitar hangtartomanya nagyobb.
A gitar hurszama nagyobb.