Kapitel 10: Vererbung

In einem kleinen Demo-Programm bewegen sich Autos und Motorräder von links nach rechts über das Fenster. Zusätzlich fliegen Sterne in Parabelbahnen.

a) Schlechte Implementierung

Es bietet sich an, Klassen Stern, Auto und Motorrad für die bewegten Objekte zu erstellen sowie eine zusätzliche Klasse AnimationStarter, in der

  • ständig neue bewegte Objekte instanziert werden,
  • alle auf dem Bildschirm befindlichen Objekte ständig weiterbewegt werden und
  • alle Objekte, die aus dem Bildschirm herausfliegen, vernichtet werden.

Klasse Stern

public class Stern {
 
    private Sprite sprite;
 
    private double vx, vy, ay;
 
    public Stern(double x, double y) {
        this.vx = Math.random() * 6 - 3;
        this.vy = Math.random() * (-15) - 5;
        this.ay = 0.3;
 
        sprite = new Sprite("/vererbung/star.png", x, y);
        sprite.strecken(0.2);
 
    }
 
    public void zeitschritt(){
 
        vy += ay;
 
        if(sprite != null) {
            sprite.verschieben(vx, vy);
        }
    }
 
    public boolean istAußerhalbDesFensters(){
        return sprite.istAußerhalbDesFensters();
    }
 
    public void vernichten(){
        sprite.vernichten();
    }
 
}

Klasse Auto

public class Auto {
 
    private Sprite sprite;
 
    private double vx, vy, ay;
 
    public Auto(double x, double y) {
        this.vx = Math.random() * 3  + 1;
        this.vy = 0;
        this.ay = 0;
 
        sprite = new Sprite("/vererbung/car2.png", x, y);
        sprite.strecken(0.2);
 
    }
 
    public void zeitschritt(){
 
        vy += ay;
 
        if(sprite != null) {
            sprite.verschieben(vx, vy);
        }
    }
 
    public boolean istAußerhalbDesFensters(){
        return sprite.istAußerhalbDesFensters();
    }
 
 
    public void vernichten(){
        sprite.vernichten();
    }
 
}

Klasse Motorrad

public class Motorrad {
 
    private Sprite sprite;
 
    private double vx, vy, ay;
 
    public Motorrad(double x, double y) {
        this.vx = Math.random() * 6 + 2;
        this.vy = 0;
        this.ay = 0;
 
        sprite = new Sprite("/vererbung/motorbike.png", x, y);
        sprite.strecken(0.2);
 
    }
 
    public void zeitschritt(){
 
        vy += ay;
 
        if(sprite != null) {
            sprite.verschieben(vx, vy);
        }
    }
 
    public boolean istAußerhalbDesFensters(){
        return sprite.istAußerhalbDesFensters();
    }
 
    public void vernichten(){
        sprite.vernichten();
    }
 
}

Klasse AnimationStarter

public class AnimationStarter implements TimerListener {
 
    private ArrayList<Stern> sterne = new ArrayList<>();
    private ArrayList<Auto> autos = new ArrayList<>();
    private ArrayList<Motorrad> motorräder = new ArrayList<>();
 
    int i = 0;
 
    public static void main(String[] args) {
 
        new AnimationStarter().start();
 
    }
 
    private void start() {
 
        Fenster f = new Fenster(800, 750);
 
        Timer timer = new Timer(this, 20);
        timer.start();
 
    }
 
 
    @Override
    public void timerSignalVerarbeiten() {
 
        i++;
        if(i % 10 == 0){
            sterne.add(new Stern(300, 600));
            autos.add(new Auto(0, Math.random() * 600));
            motorräder.add(new Motorrad(0, Math.random() * 600));
        }
 
        for(int i = 0; i < autos.size(); i++){
            Auto a = autos.get(i);
            if(a.istAußerhalbDesFensters()){
                autos.remove(a);
                a.vernichten();
            }
            a.zeitschritt();
        }
 
        for(int i = 0; i < sterne.size(); i++){
            Stern s = sterne.get(i);
            if(s.istAußerhalbDesFensters()){
                sterne.remove(s);
                s.vernichten();
            }
            s.zeitschritt();
        }
 
        for(int i = 0; i < motorräder.size(); i++){
            Motorrad m = motorräder.get(i);
            if(m.istAußerhalbDesFensters()){
                motorräder.remove(m);
                m.vernichten();
            }
            m.zeitschritt();
        }
 
    }
}

Bewertung der Implementierung

Die Implementierung hat folgende Nachteile:

  • Große Teile des Codes in den Klassen Stern, Auto und Motorrad sind identisch.
    • Die Erstellung der Klassen ist recht zeitaufwändig
    • Will man etwas in den betroffenen Codeblöcken ändern, so muss man die Änderungen in allen drei Klassen vornehmen
  • In der Klasse AnimationStarter müssen für Autos, Sterne und Motorräder jeweils extra Listen geführt werden. Dies hat zur Folge, dass sich in der Methode timerSignalVerarbeiten große Teile des Codes wiederholen.

Bessere Implementierung durch Nutzung von Vererbung

Die gemeinsamen Methoden und Attribute der Klassen Stern, Auto und Motorrad packen wir in eine Basisklasse BewegteFigur. Die Klassen Stern, Auto und Motorrad leiten wir dann von BewegteFigur ab, d.h. sie erben alle Attribute und Methoden der Basisklasse.

  • Dass eine Klasse von einer anderen Klasse ('Basisklasse') abgeleitet ist, wird durch das Schlüsselwort extends ausgedrückt.
  • Der Konstruktor der Basisklasse lässt sich aus dem Konstruktor der abgeleiteten Klasse mit den Schlüsselwort super aufrufen, siehe die nachfolgenden Quelltexte.

Die Klasse BewegteFigur

public class BewegteFigur {
 
    private Sprite sprite;
 
    private double vx, vy, ay;
 
    public BewegteFigur(String dateiname, double x, double y, double vx, double vy, double ay) {
        this.vx = vx;
        this.vy = vy;
        this.ay = ay;
 
        sprite = new Sprite(dateiname, x, y);
        sprite.strecken(0.2);
 
    }
 
    public void zeitschritt(){
 
        vy += ay;
 
        if(sprite != null) {
            sprite.verschieben(vx, vy);
        }
    }
 
    public boolean istAußerhalbDesFensters(){
        return sprite.istAußerhalbDesFensters();
    }
 
    public void vernichten(){
        sprite.vernichten();
    }
 
}

Die Klasse SternNeu

public class SternNeu extends BewegteFigur {
 
    public SternNeu(double x, double y){
        // Aufruf des Konstruktors der Basisklasse BewegteFigur:
        super("/vererbung/star.png", x, y,
                Math.random() * 6 - 3, Math.random() * (-15) - 5,
                0.3);
    }
 
}

Die Klasse AutoNeu

public class AutoNeu extends BewegteFigur {
 
    public AutoNeu(double x, double y){
        super("/vererbung/car2.png", x, y,
                Math.random() * 3  + 1, 0,0);
    }
 
}

Die Klasse MotorradNeu

public class MotorradNeu extends BewegteFigur {
 
    public MotorradNeu(double x, double y){
        super("/vererbung/motorbike.png", x, y,
                Math.random() * 6  + 2, 0,0);
    }
 
}

Die Klasse AnimationStarterNeu

public class AnimationStarterNeu implements TimerListener {
 
    private ArrayList<BewegteFigur> figuren = new ArrayList<>();
 
    int i = 0;
 
    public static void main(String[] args) {
 
        new AnimationStarterNeu().start();
 
    }
 
    private void start() {
 
        Fenster f = new Fenster(800, 750);
 
        Timer timer = new Timer(this, 20);
        timer.start();
 
    }
 
 
    @Override
    public void timerSignalVerarbeiten() {
 
        i++;
        if(i % 10 == 0){
            figuren.add(new SternNeu(300, 600));
            figuren.add(new AutoNeu(0, Math.random() * 600));
            figuren.add(new MotorradNeu(0, Math.random() * 600));
        }
 
        for(int i = 0; i < figuren.size(); i++){
            BewegteFigur f = figuren.get(i);
            if(f.istAußerhalbDesFensters()){
                figuren.remove(f);
                f.vernichten();
            }
            f.zeitschritt();
        }
 
    }
}
Drucken/exportieren
QR-Code
QR-Code schule:klassen:2017:10b:kap10 (erstellt für aktuelle Seite)