11 inheritance - User Websites on enterpriselab.ch

Werbung
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
11 INHERITANCE
1 Einleitung
Sie haben die Begriffe Klasse und Objekt bereits kennen gelernt.
Sie wissen, dass eine Klasse eine Beschreibung für gleichartige
Objekte ist. Sie definiert, welche Attribute und Operationen alle
Objekte besitzen, die zu dieser Klasse gehören. Zum Beispiel
können wir eine Klasse Personenwagen definieren. Die Klasse
definiert die gemeinsamen Attribute und Operationen aller Autos.
Anhand der Klasse Personenwagen können wir dann beliebig viele Autos, oder eben Personenwagen-Objekte, erzeugen.
Im Klassendiagramm könnte das so aussehen:
myCar
Personenwagen
modell
leistung
anzahlPersonen
starten()
beschleunigen()
bremsen()
modell = DöSchwo
leistung = 2 PS
anzahlPersonen = 5
otherCar
modell = Mercedes 500
leistung = 200 PS
anzahlPersonen = 5
So weit, so gut. Was nun, wenn wir eine Klasse für Lastwagen
schreiben sollen? Müssen wir dann nicht Attribute und Operationen, welche in der Klasse Personenwagen schon definiert sind,
nochmals definieren? Zum Beispiel haben ja auch Lastwagen einen Motor mit einer Leistung. Dies ist ein Attribut, welches für
alle Motorfahrzeuge gilt.
Was uns fehlt, ist ein übergeordnetes, allgemeineres Konzept.
11 Inheritance.doc, V10
© H. Diethelm
Seite 1/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
2 Klassenhierarchien
Die Lösung für unser Problem sieht folgendermassen aus: Wir definieren zuerst eine Klasse Motorfahrzeug. Diese enthält alle
gemeinsamen Attribute und Operationen von Motorfahrzeugen.
Im Klassendiagramm:
Motorfahrzeug
modell
leistung
starten()
beschleunigen()
bremsen()
Mit Hilfe dieser Klasse können wir nun unsere bestehende Klasse
Personenwagen sowie die neue Klasse Lastwagen auf einfachere Weise definieren: Wir sagen nur noch, welche zusätzlichen
Attribute und Eigenschaften diese Klassen haben. Gleichzeitig
legen wir fest, dass die Klassen auch über sämtliche Eigenschaften der Klasse Motorfahrzeug verfügen.
11 Inheritance.doc, V10
© H. Diethelm
Seite 2/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Wieder in UML:
Der Pfeil von der Klasse Personenwagen zur Klasse Motorfahrzeug symbolisiert, dass die Klasse Personenwagen neben ihren
eigenen Attributen und Operationen auch über all jene der Klasse
Motorfahrzeug verfügt. Man sagt, die Klasse Personenwagen
erbt die Attribute und Operationen von der Klasse Motorfahrzeug.
Man sagt auch, die Klasse Personenwagen ist von der Klasse
Motorfahrzeug abgeleitet oder die Klasse Personenwagen erweitert die Klasse Motorfahrzeug. Motorfahrzeug ist die Superklasse und Personenwagen ist die Subklasse.
Die drei Klassen bilden eine Klassenhierarchie. Geht man in der
Hierarchie nach oben, so kommt man zu immer allgemeineren
Klassen. Ein Personenwagen ist z.B. ein spezielles Motorfahrzeug; man spricht deshalb auch von einer is-a-Beziehung. Geht
man nach unten, findet man immer spezialisiertere Klassen.
11 Inheritance.doc, V10
© H. Diethelm
Seite 3/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
Aufgabe 1:
a) Erweitern Sie obige Klassenhierarchie um folgende Elemente:
- Eine Klasse für Motorräder
- Eine Klasse für Cabriolets
Zeichnen Sie ein paar Attribute und Operationen ein, welche
typisch für die beiden neuen Klassen sind.
b) Überlegen Sie sich, wie eine Klasse Fahrrad in die Klassenhierarchie integriert werden könnte. Zeichnen Sie ihren Vorschlag im Klassendiagramm ein.
11 Inheritance.doc, V10
© H. Diethelm
Seite 4/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
3 Vererbung versus Aggregation
Die Gefahr besteht, mit der Zeit zu sehr grossen und unübersichtlichen Klassenhierarchien zu kommen. Beispielsweise
könnte man versucht sein, zwischen Motorfahrzeugen mit Elektroantrieb und solchen mit Verbrennungsmotor zu unterscheiden. Das würde aber zu einer Verdoppelung von Klassen führen, denn es gibt ja für beide Antriebsarten Personenwagen.
Hier wäre vielmehr ein Aggregations-Beziehung (vgl. has-aBeziehung) zwischen der Klasse Motorfahrzeug und einer Klasse Motor angezeigt. Die Klasse Motor könnte dann ihrerseits wieder abgeleitet werden.
In UML:
Motor
leistung
Motorfahrzeug
Elektromotor
Verbrennungsmotor
Wichtig zu wissen ist, dass es nicht DAS Klassendiagramm
für ein bestimmtes Problem gibt! Die möglichen Lösungen sind
meist sehr vielfältig und Modellieren ist ein iterativer, d.h. sich wiederholender Prozess.
11 Inheritance.doc, V10
© H. Diethelm
Seite 5/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
4 Umsetzung in Java
Wie man in Java eine Klasse definiert, das wissen Sie bereits. Neu
für Sie ist, wie man in Java eine Klasse von einer anderen ableitet. Und eigentlich haben Sie auch das schon x-mal gemacht:
class
...
}
MyApplet
extends
Applet
{
Mit dem Schlüsselwort extends kann man definieren, von welcher Klasse eine neue Klasse abgeleitet sein soll.
In UML:
11 Inheritance.doc, V10
© H. Diethelm
Seite 6/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
Das Motorfahrzeug-Beispiel würde demnach folgendermassen in
Java umgesetzt:
class Motorfahrzeug {
public String modell; // Vorsicht mit public!
public double leistung;
public void starten() {
...
}
}
class Personenwagen extends Motorfahrzeug {
public int anzahlPersonen;
// Vorsicht mit public!
...
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 7/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
5 Zugriff auf Instanzvariablen und Methoden der Superklasse(n)
5.1 Schlüsselwort public
Aus abgeleiteten Klassen kann grundsätzlich auf alle publicElemente der Superklasse (und wiederum derer Superklasse
etc.) zugegriffen werden, wie wenn diese in der eigenen Klasse
definiert wären.
Im obigen Beispiel kann also eine Methode in der Klasse Personenwagen auf die Instanzvariablen modell und leistung zugreifen, welche in Motorfahrzeug deklariert sind. Ebenso kann
sie die Methode starten() direkt aufrufen:
class Personenwagen extends
Motorfahrzeug {
...
public void demoMethode() {
leistung = 2000.0;
starten();
}
...
11 Inheritance.doc, V10
© H. Diethelm
Seite 8/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
5.2 Schlüsselwort private
Hingegen kann aus einer abgeleiteten Klasse auf keine privateElemente der Superklasse (weder Instanzvariablen noch Methoden) zugegriffen werden.
Guter Programmierstil ist, Instanzvariablen möglichst als
private zu deklarieren! Zugriffe auf die Instanzvariablen erfolgen dann ausschliesslich über entsprechende set- und getZugriffsmethoden, welche auch allfällige Integritätsbedingungen sicherstellen. Zudem kann so gegebenenfalls die interne
Repräsentation einfach und lokal in der Klasse geändert werden.
class Motorfahrzeug {
private String modell;
private double leistung;
public void setLeistung(double l) {
if (l > 0.0) leistung = l;
}
public void starten() {
...
}
}
class Personenwagen extends Motorfahrzeug {
...
public void demoMethode() {
setLeistung(2000.0);
starten();
}
...
11 Inheritance.doc, V10
© H. Diethelm
Seite 9/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
5.3 Schlüsselwort protected
Die Zugriffsregel für private-Elemente kann zu einschränkend
sein. Aus diesem Grund gibt es in Java das Schlüsselwort protected, welches erlaubt, Elemente einer Klasse für die abgeleiteten Klassen zugänglich zu machen, gegen "aussen" aber zu
schützen.
Fehlt ein Schlüsselwort private, protected oder public, so
wird der Zugriff gemäss untenstehender Tabelle geregelt. Wie Sie
sehen, wird dann der Zugriff relativ restriktiv gehandhabt.
Zugriff von:
eigener
Klasse
Klasse
Unterklasse Nicht-Unterim gleichen aus andeklasse aus
Package
rem Packa- anderem
ge
Package
private
ja
nein
nein
nein
-
ja
ja
nein
nein
protected
ja
ja
ja*
nein
public
ja
ja
ja*
ja*
(*) Die Klasse muss dann natürlich importiert sein.
Bemerkung:
Ein Package fasst Klassen zusammen, die eng miteinander kooperieren oder die zumindest konzeptionell zusammengehören.
Die Klassen müssen dazu auch im gleichen Verzeichnis gespeichert sein (siehe später).
11 Inheritance.doc, V10
© H. Diethelm
Seite 10/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Aufgabe 2:
Wir möchten eine Klassenhierarchie für Grafiken entwickeln (z.B.
für ein Grafikprogramm).
Eine Grafik soll aus Kreisen oder Rechtecken bestehen. Beides
sind Figuren. Gesucht sind Klassen, welche die wesentlichen Informationen sowie die notwendigen Methoden gemäss folgender
Beschreibung enthalten:
ƒ Das Rechteck ist durch seine Breite und Höhe definiert, der
Kreis durch seinen Radius.
ƒ Kreis und Rechteck ist gemeinsam, dass sie sich an einem
bestimmten Ort auf dem Bildschirm befinden. Dieser ist definiert
durch die linke, obere Ecke des Rechtecks oder eines gedachten, den Kreis umgebenden Rechtecks.
ƒ Beide haben eine Methode display(), um sich auf dem
Bildschirm zu zeichnen, sowie einen Konstruktor, welcher die
nötigen Parameter für eine vollständige Festlegung eines
Kreis- bzw. eines Rechteck-Objekts aufweist.
ƒ Schliesslich soll eine Methode moveTo() zum Verschieben
von Kreis- und Rechteck-Objekten an einen neuen Ort vorhanden sein. Die Methode hat als Parameter die Koordinaten
des neuen Ortes.
Zeichnen Sie ein Klassendiagramm und versuchen Sie, die beiden Klassen Rectangle und Circle sowie die übergeordnete
Klasse Figure gemäss den obigen Angaben zu programmieren.
Überlegen Sie sich, welche Instanzvariablen und Methoden in welche Klassen gehören. Die Regel heisst: Gemeinsame "Dinge"
gehören in die Superklasse.
Studieren Sie die Unterlagen noch nicht weiter, denn Sie wollen ja
selber eine Lösung erarbeiten!
11 Inheritance.doc, V10
© H. Diethelm
Seite 11/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
11 Inheritance.doc, V10
© H. Diethelm
Seite 12/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
Klassendiagramm in UML:
Figure
-xPos:int
-yPos:int
+Figure(x:int, y:int)
+moveTo(x:int, y:int):void
+setXPos(x:int):void
+setYPos(y:int):void
+getXPos():int
+getYPos():int
Circle
Rectangle
-radius:int
-width:int
-height:int
+Circle(x:int, y:int, r:int)
+setRadius(r:int):void
+getRadius():int
+display(g:Graphics):void
+Rectangle(x:int, y:int, w:int, h:int)
+setSize(w:int, h:int):void
+getWidth():int
+getHeight():int
+display(g:Graphics):void
Bemerkung:
Obiges Klassendiagramm hält explizit Sichtbarkeit, Datentypen,
formale Parameter sowie die Datentypen der Rückgabewerte fest.
Die UML schreibt diese Vollständigkeit nicht vor. Entsprechend
dem Kontext, in dem das Klassendiagramm verwendet wird,
kann man teilweise oder ganz auf diese Präzisierungen verzichten.
11 Inheritance.doc, V10
© H. Diethelm
Seite 13/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Java-Sourcecode:
class Figure {
private int xPos;
private int yPos;
public Figure(int x, int y) {
xPos = x;
yPos = y;
}
public void moveTo(int x, int y) {
xPos = x;
yPos = y;
}
public void setXPos(int x) {
xPos = x;
}
public void setYPos(int y) {
yPos = y;
}
public int getXPos() {
return xPos;
}
public int getYPos() {
return yPos;
}
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 14/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
import java.awt.Graphics;
class Circle extends Figure {
private int radius;
public Circle (int x, int y, int r) {
super(x, y);
radius = r;
}
public void setRadius(int r) {
radius = r;
}
public int getRadius() {
return radius;
}
public void display(Graphics g) {
g.drawOval(getXPos(), getYPos(),
2*radius, 2*radius);
}
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 15/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
import java.awt.Graphics;
class Rectangle extends Figure {
private int width;
private int height;
public Rectangle(int x, int y, int w, int h){
super(x, y);
width = w;
height = h;
}
public void setSize(int w, int h) {
width = w;
height = h;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void display(Graphics g) {
g.drawRect(getXPos(), getYPos(),
width, height);
}
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 16/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Bemerkungen:
ƒ Alle Instanzvariablen sind private deklariert. Zugriffe erfolgen ausschliesslich über set- und get-Zugriffsmethoden.
ƒ Jedes Rechteck-Objekt ist auch ein Figur-Objekt. Ebenso ist jedes Kreis-Objekt ein Figur-Objekt. Erstere sind Spezialisierungen von letzteren. Deshalb muss der Konstruktor Rectangle() in einem ersten Schritt ein Figur-Objekt konstruieren und darf erst in einem zweiten Schritt rechteckspezifische Belange berücksichtigen! Mit super (vgl. super(),
super.variable, super.methode()) kann explizit Bezug
auf die Oberklasse genommen werden. So ruft super(x, y)
den entsprechenden Konstruktor der Oberklasse Figure
auf.
ƒ Besitzt die Oberklasse gar keinen explizit deklarierten Konstruktor, so ist ein super()-Aufruf nicht zwingend notwendig.
Es wird dann sozusagen ein leerer Default-Konstruktor aufgerufen.
ƒ Besitzt die Oberklasse einen explizit deklarierten Konstruktor ohne Parameter, so ist ein super()-Aufruf ebenfalls nicht
zwingend erforderlich; er wird in diesem Fall automatisch aufgerufen.
Aufgabe 3:
Angenommen die Instanzvariablen xPos und yPos der Klasse
Figure seien nur protected deklariert. Schreiben Sie für diesen
Fall nochmals den Quellencode für die Klassen Rectangle und
Circle.
11 Inheritance.doc, V10
© H. Diethelm
Seite 17/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
6 Anwendung der eigenen Grafik-Klassen
Die Klassen, welche wir in der obigen Aufgabe entwickelt haben,
können wir jetzt zum Beispiel in einem Applet einsetzen:
import java.awt.*;
import java.applet.Applet;
public class Figurlet extends Applet {
private Rectangle myRectangle;
private Circle myCircle;
public void init() {
myRectangle = new Rectangle(100,100,20,40);
myCircle = new Circle(200,100,30);
}
public void paint(Graphics g) {
myRectangle.display(g);
myCircle.display(g);
}
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 18/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Schliesslich könnten wir in unserem Applet auch die moveTo()Methoden aufrufen (z.B. als Antwort auf ein Event):
...
myRectangle.moveTo(newX, newY);
myCircle.moveTo(newX, newY);
...
Bemerkung:
Beachtenswert ist, dass wir die Methode moveTo() bei einem
Rechteck- bzw. bei einem Kreis-Objekt aufrufen. Effektiv ist die
Methode aber in der Klasse Figure definiert. Rechteck- und
Kreis-Objekt sind aber gleichzeitig auch Figur-Objekte!
Klassendiagramm in UML:
11 Inheritance.doc, V10
© H. Diethelm
Seite 19/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
7 Zuweisung von Objekten zu Referenzvariablen
Ein Objekt einer bestimmten Klasse (vgl. Rectangle) darf man
jederzeit einer anderen Referenzvariablen derselben Klasse
zuweisen (vgl. rect2). Auch dürfen gleichzeitig mehrere Referenzvariablen ein und dasselbe Objekt referenzieren (vgl.
rect2 und rect3). Der Spezialwert null für "kein Objekt" kann
immer zugewiesen werden.
...
Rectangle rect1 = new Rectangle(10,10,20,30);
Rectangle rect2 = rect1;
Rectangle rect3 = rect2;
rect1 = null;
...
Gemäss Vererbungshierarchie gilt, dass ein Rechteck-Objekt
gleichzeitig auch ein Figur-Objekt ist. Deshalb ist es auch möglich, ein Rectangle-Objekt einer Figure-Referenzvariablen
zuzuweisen.
...
Rectangle rect = new Rectangle(10,10,20,30);
Figure fig = rect;
...
Allerdings sind wir jetzt bezüglich der Möglichkeiten eingeschränkt, welche wir mit fig haben! Wichtig zu wissen ist, dass
ein Objekt seine Klassenzugehörigkeit und seine Interna
IMMER beibehält, auch wenn es von einer Referenzvariablen einer Oberklasse referenziert wird. (Es findet also keine Umwandlung der internen Darstellung statt, wie das bei der Zuweisung von
Werten elementarer Datentypen passieren kann.) Allerdings ändert sich die Betrachtungsweise des Objektes; man betrachtet das
Objekt sozusagen durch die "Brille der Oberklasse":
11 Inheritance.doc, V10
© H. Diethelm
Seite 20/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
ƒ
Über fig kann nur auf die public Methoden und Instanzvariablen der Klasse
Figure zugegriffen werden, denn fig
kann ein Rectangle-, Circle- oder Figure-Objekt referenzieren!
ƒ
Weiter ist ein Zugriff auf Methoden und Instanzvariablen von Oberklassen möglich,
falls diese zugänglich sind.
...
rect = fig; // => Compilerfehler !!
rect = (Rectangle) fig; // => korrekt
...
Weil fig auch ein Circle-Objekt referenzieren kann, ist die erste
Zuweisung nicht erlaubt! Der Compiler wird mit einer Fehlermeldung reagieren, weil man eine "allgemeinere Referenz" einer
"spezielleren Referenz" zuweisen will.
Die zweite Zuweisung mit dem Cast ist hingegen korrekt. Der Cast
ist sozusagen eine Zusicherung/ein Versprechen, dass fig ein
Rectangle-Objekt referenziert und die Zuweisung demzufolge
möglich ist. Stellt sich zur Laufzeit heraus, dass dem nicht so ist,
wird ein Laufzeitfehler bzw. eine Exception die Folge sein!
11 Inheritance.doc, V10
© H. Diethelm
Seite 21/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
8 Überschreiben von Methoden und Polymorphismus
In unserem Beispiel fällt auf, dass beide Klassen Rectangle
und Circle je eine Methode display() haben. Von der Idee
her machen beide Methoden dasselbe, sie zeichnen ihr Objekt.
Eigentlich könnte man wünschen, dass jede Figur eine display()-Methode hat. Wie die Methode eine Figur zeichnet,
hängt dann von der konkreten Situation bzw. vom konkreten
Objekt ab. Ist die Figur ein Rechteck wird ein Rechteck gezeichnet etc.
Genau das kann Java: Wir definieren zusätzlich auch in der
Klasse Figure eine Methode display(). Diese Methode wird
genau dann aufgerufen, falls fig ein Figur-Objekt referenziert.
Referenziert fig aber ein Objekt einer Unterklasse, z.B. ein
Kreis-Objekt, so wird automatisch die korrespondierende Methode display() der Unterklasse Circle aktiviert.
class Figure {
...
public void display(Graphics g) {
g.drawString("I'm a Figure.", xPos, yPos);
}
...
}
11 Inheritance.doc, V10
© H. Diethelm
Seite 22/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
class Circle extends Figure {
...
public void display(Graphics g) {
g.drawOval(getXPos(), getYPos(),
2*radius, 2*radius);
}
...
}
class Rectangle extends Figure {
...
public void display(Graphics g) {
g.drawRect(getXPos(), getYPos(),
width, height);
}
...
}
Die Methode display() ist sowohl in der Klasse Figure wie
auch in den Klassen Circle und Rectangle definiert. Die Methodenköpfe (Signaturen) müssen dabei absolut gleich sein!
Man nennt dies Überschreiben einer Methode.
11 Inheritance.doc, V10
© H. Diethelm
Seite 23/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
Damit können wir nun in einer Anwendung folgendes tun:
...
Figure fig1 = new Figure(10, 120);
Figure fig2 = new Rectangle(10, 10, 20, 30);
Figure fig3 = new Circle(10, 60, 40);
public void paint(Graphics g) {
fig1.display();
fig2.display();
fig3.display();
}
...
fig1 bis fig3 sind drei Referenzvariablen für Figur-Objekte. Ihnen werden je ein Figure-, Rectangle- und Circle-Objekt zugewiesen. In der paint()-Methode wird bei allen drei Referenzvariablen die display()-Methode aufgerufen.
Weil die Methode display() in den abgeleiteten Klassen überschrieben ist, geschieht folgendes:
Es wird bei allen drei Aufrufen immer diejenige Variante von
display() ausgeführt, welche zur Klasse bzw. zum Objekt
gehört, das referenziert wird.
ƒ
fig1.display() => Text ausgeben
ƒ
fig2.display() => Rechteck zeichnen
ƒ
fig3.display() => Kreis zeichnen
Dies ist ein sehr mächtiges Konzept und wird in der objektorientierten Programmierung oft angewendet. Es erlaubt, unabhängigen
Code zu schreiben. Wenn eine neue Figur-Klasse, z.B. für Dreiecke, eingeführt wird, so sind die Änderungen am bestehenden
Code minimal. Das Konzept segelt auch unter dem Begriff Polymorphismus oder frei übersetzt "Vielgestaltigkeit".
11 Inheritance.doc, V10
© H. Diethelm
Seite 24/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
Klassendiagramm in UML:
is-a
Applet
Figurlet
has-a
3
Figure
is-a
is-a
+moveTo()
+display()
Rectangle
Circle
+display()
+display()
9 Abstrakte Klassen
Ist die Sachlage so, dass Objekte der Klasse Figure keinen Sinn
machen, so kann die Klasse als abstract deklariert werden. Es
ist dann nicht mehr möglich, Objekte dieser Klasse zu instanzieren. Damit wird auch die Methode display() in der Klasse Figure nie mehr zur Ausführung gelangen.
Trotzdem macht es Sinn, eine abstrakte Methode display()
bzw. den entsprechenden Methodenkopf in der Klasse Figure zu
deklarieren. Damit wird zum Ausdruck gebracht, dass sämtliche
Figur-Objekte eine Methode display() besitzen, die allerdings in
den Unterklassen noch implementiert werden müssen. Die abstrakte Klasse Figure garantiert damit ein bestimmtes Verhalten für sämtliche Figur-Objekte.
11 Inheritance.doc, V10
© H. Diethelm
Seite 25/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
Randbemerkung: Ein Interface bzw. eine Schnittstellenklasse ermöglicht Ähnliches, aber ohne Gebrauch der klassischen Vererbung (siehe später).
Klassendiagramm in UML:
Figure
-xPos:int
-yPos:int
+Figure(x:int, y:int)
+moveTo(x:int, y:int):void
+setXPos(x:int):void
+setYPos(y:int):void
+getXPos():int
+getYPos():int
+display(g:Graphics):void
Circle
Rectangle
-radius:int
-width:int
-height:int
+Circle(x:int, y:int, r:int)
+setRadius(r:int):void
+getRadius():int
+display(g:Graphics):void
+Rectangle(x:int, y:int, w:int, h:int)
+setSize(w:int, h:int):void
+getWidth():int
+getHeight():int
+display(g:Graphics):void
11 Inheritance.doc, V10
© H. Diethelm
Seite 26/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
abstract class Figure {
...
public abstract void display(Graphics g);
...
}
class Circle extends Figure {
...
public void display(Graphics g) {
g.drawOval(getXPos(), getYPos(),
radius, radius);
}
...
}
class Rectangle extends Figure {
...
public void display(Graphics g) {
g.drawRect(getXPos(), getYPos(),
width, height);
}
...
}
...
Figure fig1 = new Rectangle(10, 10, 20, 30);
Figure fig2 = new Circle(10, 60, 40);
public void paint(Graphics g) {
fig1.display(); fig2.display();
}
...
11 Inheritance.doc, V10
© H. Diethelm
Seite 27/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
10 Beispiel AWT
Abstract:
ƒ
allgemeiner plattformunabhängiger Ansatz
Window:
ƒ
Umgang mit Fenstersystemen
Toolkit:
ƒ
sehr grosse Klassenbibliothek
10.1 Bildschirmausgabe in Windowsystemen
"Nicht der Programmierer bestimmt, wann etwas auf dem Bildschirm dargestellt wird, sondern der User."
Entsprechend bestimmt nicht das Programm, wann etwas auf
dem Bildschirm dargestellt werden soll, sondern das Windowsystem.
Konsequenzen:
ƒ Das Programm muss zu jedem Zeitpunkt in der Lage sein, die
komplette Bildschirmausgabe zu rekonstruieren.
ƒ Das Programm muss das Windowsystem über neu anzuzeigende Bildschirminhalte informieren.
Das Windowsystem ruft die paint()-Methode eines Applets
oder Programms auf, sobald das Applet gezeichnet werden soll.
Das Applet oder Programm ruft seine repaint()-Methode auf,
sobald es wünscht, neu gezeichnet zu werden.
11 Inheritance.doc, V10
© H. Diethelm
Seite 28/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
10.2 Wichtige Klassen für das elementare Zeichnen
Graphics: Stellt die eigentlichen Zeichenoperationen zur Verfügung. Graphics-Objekte dienen als eine Art "Zeichenblatt". Sie
werden nicht selbst instanziert, sondern vom Ausgabegerät zur
Verfügung gestellt (z.B. Bildschirm, Drucker). Zusätzlich speichert
die Klasse den aktuellen Zustand des Gerätes (z.B. Zeichenfarbe,
Font, Clipping-Region).
Color: Farben
Font: Schrifttypen
Point: Punkt mit Koordinaten x, y
Dimension: Grössenangabe mit width und height
Rectangle: Rechteck
Polygon: n-Eck
Image: abstrakte Klasse für Bitmap-Grafiken
AWT-Klassenhierarchie (Ausschnitt 1):
Object
equals():boolean
Graphics
drawLine(): void
getFont(): Font
Color
Font
Point
Dimension
Rectangle
Polygon
Image
black: Color
name:String
size:int
x:int
y:int
height:int
width:int
height:int
width:int
npoints:int
xpoint:int[]
SCALE_FAST:int
darker():Color
getName():String
getX():double
move():void
equals():boolean
setSize():void
move():void
resize():void
addPoint():void
inside():boolean
getHeight():int
11 Inheritance.doc, V10
© H. Diethelm
Seite 29/31
Abteilung Informatik, Fach Programmieren
FHZ
Hochschule für Technik+Architektur Luzern
11 INHERITANCE
10.3 Wichtige Klassen für GUIs
Component: Das sind die Grundbausteine für ein GUI. Alles,
was man sieht, ist ein Component! Die Klasse Component hat
sehr viele Methoden. Im Zweifelsfalle hier eine Methode suchen!
Canvas: Die einfachste Zeichenoberfläche (vgl. wie Applet ohne
Funktionalität). Besitzt im Wesentlichen ein Graphics-Objekt.
Container: Ein Behälter für Components. Die Anordnung der
Bildelemente wird durch das Layout des Containers bestimmt. Typische Container sind Panel und Window. Ermöglicht eine
hierarchische Gestaltung des GUI.
Panel: Ein Objekt zum Zusammenfassen grösserer Sinneseinheiten in einem Fenster.
Window: Ein einfaches Fenster-Objekt.
Frame: Ein "richtiges" Fenster-Objekt. Hat einen Titelbalken,
kann vom Benutzer verkleinert und vergrössert werden, kann ein
Menü haben usw. (vgl. Java-Programme).
Button: Druckknopf
Checkbox: Ankreuzfeld
Choice: Auswahlmenü (Pull-Down)
List: Auswahlmenü
Label: statischer Text
Scrollbar: Schieberegler
TextField: Texteingabe (einzeilig)
TextArea: Texteingabefeld (mit mehreren Zeilen)
11 Inheritance.doc, V10
© H. Diethelm
Seite 30/31
FHZ
Hochschule für Technik+Architektur Luzern
Abteilung Informatik, Fach Programmieren
11 INHERITANCE
AWT-Klassenhierarchie (Ausschnitt 2):
Object
equals():boolean
Component
paint():void
repaint():void
update():void
Checkbox
getLabel():String
setState():void
Choice
Container
addItme():void
remove():void
add():void
remove():void
paint():void
setLayout():void
Panel
ScrollPane
Button
Canvas
List
Label
TextComponent
CENTER:int
getLabel():String
setLabel():void
paint():void
getRows():int
select():void
setText():void
Scrollbar
VERTICAL:int
getText():String
select():void
getMinimum():int
getValue():int
Window
SCROLLBARS_
NEVER:int
addNotify():void
setLayout():void
show():void
toBack():void
Applet
Dialog
Frame
init():void
setModal():void
setTitle():void
setMenuBar():voi
d
FileDialog
LOAD:int
READ:int
getFile():String
getMode():int
Ein Container ist bekanntlich ein Behälter (vgl. Aggregat) für Components (sogenanntes Composite-Entwurfsmuster):
Component
0..n
Container
add():void
remove():void
paint():void
setLayout():void
paint():void
repaint():void
update():void
Button
getLabel():String
setLabel():void
Label
Scrollbar
CENTER:int
VERTICAL:int
setText():void
getMinimum():int
getValue():int
Panel
addNotify():void
Applet
init():void
11 Inheritance.doc, V10
© H. Diethelm
Seite 31/31
Zugehörige Unterlagen
Herunterladen