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:
 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

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:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 


 

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:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 


 

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:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 


 

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.