Inhaltsverzeichnis
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
undMotorrad
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 MethodetimerSignalVerarbeiten
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(); } } }