Skript Raumplanung -Text Vererbung

Werbung
Kü /Info Oberstufe
OOP - Raumplanung
Sj. 2012/2013
Was ist Vererbung und warum sollte man das verwenden?
 Video:
o Video „OOP - Vererbung“ - http://youtu.be/vEKnrRfIJLw
o Vererbung.wmv
Es ist sehr unbefriedigend, große Programmtextabschnitte durch Kopieren in andere Klassen
zu übertragen, ohne dass in weiten Teilen auch nur eine Zeile geändert wird (will man nachträglich z.B. dort etwas ändern, so muss man das an vielen Stellen tun und verliert schnell
den Überblick). Absolut naheliegend ist, diese Abschnitte in eine eigene „Datei“
auszugliedern, um dann jedes Mal darauf zuzugreifen (oder dafür eigene Prozeduren zu benennen). In der OO ist das geeignete Mittel dafür aber keine Datei, sondern eine neue Klasse.
Das ist aber nicht nur einfach eine andere Schreibweise, dahinter steckt viel mehr – es geht
um eine neue Art von Abstraktion.
Beispiel:
Die Möbelklassen bisher beschreiben konkrete Objekte, nun wird aber von allen Möbelklassen eine übergeordnete Klasse Moebel geschaffen, die alle Attribute und Methoden enthält,
die die nun untergeordneten konkreten Möbelklassen gemeinsam hatten. Diese übergeordnete Klasse Moebel beschreibt selbst kein konkretes Objekt (was genau sollte den ein Moebel
auch sein ), sie ist wie eine Art „Sammeleimer“ für alle Attribute und Methoden, die die
Unterklassen gemeinsam brauchen.
Dadurch muss man die Attribute und Methoden nun nur noch einmal in der Oberklasse
schreiben und die Unterklassen können dann automatisch darauf zugreifen (mit einer Einschränkung: die Attribute und Methoden müssen public oder protected sein, sind sie auf private
gesetzt, so kann eine Unterklasse nicht darauf zugreifen). In den konkreten Möbelklassen
wie Tisch und Stuhl selbst stehen nur noch die Attribute und Methoden, die nur die spezielle
Klasse selbst benötigt.
Kü /Info Oberstufe
OOP - Raumplanung
Sj. 2012/2013
abstract
Beschreibt die Oberklasse so wie hier selbst kein konkretes Objekt, sondern ist nur ein „abstrakter“ Sammel-Eimer, so wird die Oberklasse auch als abstract gekennzeichnet. Man verhindert dadurch, dass von ihr konkrete Objekte gebildet werden können. In unserem Fall ist
das auch sinnvoll, denn sie dient nur dem Sammeln von Attributen und Methoden, aber ein
allgemeines „Moebel-Objekt kann die Leinwand gar nicht verarbeiten, es darf also auch nicht
erzeugt werden.
Wichtig: eine Oberklasse, die als „abstract“ gekennzeichnet ist, muss mindestens eine abstrakte Methode haben – d.h. eine Methode, die nicht in dieser Klasse selbst implementiert
wird, dafür aber durch ihre Kennzeichnung als „abstract“ erzwingt, dass jede Unterklasse sie
implementier (siehe Kapitel Probleme…)t.
Bsp.: public abstract void test(); <-ohne geschweifte Klammer, nur die Signatur und dann
ein Semikolon
protected/public
Gegenüber der Methode gibAktuelleFigur() der ursprünglichen Klassendefinition hat
sich außerdem die Angabe zur Sichtbarkeit geändert. Weshalb das notwendig ist, kann
man leicht feststellen, wenn man es bei private belässt: Bei dieser Definition kann die
Methode, die nun in einer anderen Klasse steht, nicht aufgerufen werden. protected
macht eine Methode innerhalb des gesamten Paketes sichtbar, nicht aber nach außen (dafür müsste es auf public gesetzt sein).
extends
Es ergibt sich das Problem, dass unser Projekt nun zwar eine neue Klasse hat, BlueJ und
JAVA aber nichts davon wissen, dass die Möbelklassen ihre Attribute und Methoden von
der Klasse Moebel erben sollen. Das müssen wir in den Klassentext einarbeiten. Der Kopf
wird ergänzt um extends Moebel .
Nun weiß JAVA beim Übersetzen, dass es dort nach den fehlenden Attributen und Methoden
nachsehen kann.
Probleme, die entstehen, wenn man mit einer Oberklasse Moebel arbeitet
Wenn wir die gemeinsamen Methoden in die neue Klasse Moebel ausgegliedert haben und
die verkürzte Methode gibAktuelleFigur() in der konkreten Möbelklasse – z.B. Stuhl – verblieben ist, dann kennt die Klasse Moebel die Methode gibAktuelleFigur() nicht. Es gibt aber Methoden in Moebel, die darauf zugreifen! Das muss zu einem Fehler führen. Wir können das auf
zwei Arten lösen:
1. Wir erstellen eine eigene Methode gibAktuelleFigur() in Moebel, die nichts tut (z.B. leer).
In diesem Fall wird die Methode von Moebel durch die erbende Klasse überschrieben.
2. Wir erstellen einen reinen Methodenkopf und fügen ihm das Wort abstract hinzu. In
diesem Fall wird unsere Klasse aber notwendig eine abstrakte Klasse, also eine Klasse, von der keine Objekte erzeugt werden können. Viele andere Beispiele für die unter 2. beschriebene Variante finden wir in den von uns verwendeten Grafikklassen,
Kü /Info Oberstufe
OOP - Raumplanung
Sj. 2012/2013
z.B. Ellipse2D, von der selbst keine Objekte erzeugt werden, sondern nur von Ellipse2D.Double und Ellipse2D.Float
Merke: In einer Klasse, die als abstract definiert ist, können Methoden ebenfalls als
abstract definiert werden. In diesem Falle braucht man für die Methode keine konkrete Implementierung angeben, es reicht der Methodenkopf. Die konkrete Implementierung muss dann aber in der Unterklassen erfolgen.
Beachte: die Methodensuche fängt immer in der Klasse des gerade betrachteten
Objektes an und arbeitet sich dann von Oberklasse zu Oberklasse nach oben hin vor,
bis sie eine Methode gefunden hat, die passt. Findet man auf dem Vererbungsweg
keine passende Methode (also sowohl in der Klasse, in der sie aufgerufen wurde, also auch in einer der Oberklassen), so gibt es eine Fehlermeldung.
Die verbleibende Klassendefinition von Tisch ist dann nur noch sehr kurz:
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
/**
* Ein Tisch, der manipuliert werden kann und sich ...
*/
public class Tisch extends Moebel
{
public Tisch()
{
xPosition = 120;
yPosition = 150;
orientierung = 0;
farbe = "rot";
istSichtbar = false;
breite = 120;
tiefe = 100;
}
/**
* Berechnet das zu zeichnende Shape anhand der gegebenen Daten
*/
protected Shape gibAktuelleFigur()
{
Shape tisch = new Ellipse2D.Double(0 , 0, breite, tiefe);
Rectangle2D umriss = tisch.getBounds2D();
// nun noch transformieren:
AffineTransform t = new AffineTransform();
t.translate(xPosition, yPosition);
t.rotate(Math.toRadians(orientierung),
umriss.getX()+umriss.getWidth()/2,
umriss.getY()+umriss.getHeight()/2);
return t.createTransformedShape(tisch);
}
}
Herunterladen