GObjekt, Applet

Werbung
Übungsblatt 6
10
Geometrisches Objekt
Nun ist die Zeit, alle geometrische Objekte unter einer gemeinsamen Oberklasse zu versammeln d.h.
sie in eine Klassenhierarchie zu organisieren. Die Idee, die dahinten steht ist, dass alle Objekte
dieser Klassen unter einem gemeinsamen Typ verarbeitet werden können, solange man ihre gemeinsame Charakteristiken benutzt. Was sollen sie gemeinsam haben? Hierbei kommen die folgende
Methoden in Betracht: flaeche(), umfang(), eingabe(), art() und konvex().
Da dieser neue Typ nur eine Abstraktion der existierenden Objekten ist und zwar keine reelle
Objekte darstellt, soll man es versichern, dass niemand ein Objekt dieser Klasse erzeugen kann. Das
wird mit dem Schlüßelwort abstract gemacht. Dieses Wort soll auch bei jeder Methode stehen,
die in diesem Objekt nicht zu implementieren ist. Damit wir nicht zu viele neue Methoden später
implementieren müssen, werden wir hier ein Kompromiss machen: nur eingabe() und art() werden
abstrakt sein. Methoden flaeche() und umfang() werden eher immer Null zurückliefern (nutzbar
bei Punkt und Strecke) und die Methode konvex() hier soll immer true liefern.
Sei der Name der Klasse GObjekt. Sie soll also so aussehen:
public abstract class GObjekt {
public double flaeche() {
return 0;
}
public double umfang() {
return 0;
}
public boolean kovex() {
return true;
}
public abstract void eingabe();
public abstract String art();
}
Nun sollen Sie die Klassenhierarchie aktualisieren. Machen Sie diese Klasse zur Oberklasse
von Klassen: Punkt, Strecke, Dreieck, Viereck und Ellipse. Bei den Klassen Punkt und Strecke,
werden Sie danach die Methode public String art() implementieren. Schreiben Sie sie einfach
so, dass sie die Strings „Punkt“ bzw. „Strecke“ zurückliefern.
18
Positionieren
Bis nun konnten Sie bemerken, dass zurzeit kein Objekt leicht positionierbar ist (manche sind es
auch gar nicht). Wie kann man das tun? Zum Beispiel könnte man bei der Klasse Viereck alle vier
Punkte ständig verschieben, indem man ihre Koordinaten entsprechend ändert. Aber dies würde unser
Anfangsviereck schnell deformieren wegen akkumulativer Fehler, die bei den Rechnenoperationen
über double entstehen. Um diesem Problem umzugehen, werden wir zur Basisklasse einen Punkt
als Attribut einfügen, der zum Positionieren des Koordinatensystems des Objekts dienen wird. Egal
wie wir diese Position ändern, wird sie nicht die Form des Objekts beeinflussen. Aber Achtung!
Hier können wir die Klasse Punkt nicht benutzen, da sie selbst ein GObjekt ist (überlegen Sie was
wären die Nachfolgen). Stattdessen werden wir zur Klasse GObjekt zwei neue Variablen protected
double px = 0, py = 0; einfügen. Ihre Anfangswerte werden Nullen sein. Danach werden Sie eine
neue Methode public GObjekt positionieren(double x, double y) schreiben, die diese zwei
Werte entsprechend einstellt und this als Resultat zurückliefert.
public abstract class GObjekt {
protected double px = 0, py = 0;
// ...
public GObjekt positionieren(double x, double y) {
px = x;
py = y;
return this;
}
}
Zeiger this wird am Ende zurückgeliefert, damit man die Objekte bequemer erzeugen kann:
// Nicht so! Obwohl es nicht verboten ist.
GObjekt d = new Dreieck();
d.positionieren(5,5);
// sondern so
GObjekt d = (new Dreieck()).positionieren(5,5);
10.2
Schnittstellen
Nun kommen wir zu einem neuen Begriff: Schnittstelle (engl. interface). In Java dient eine Schnittstelle als Modell für eine Menge der Funktionalitäten, die in einer Klasse zu implementieren sind.
Somit ist sie einer abstrakten Klasse ähnlich. Der erste Unterschied ist, dass man in einer Schnittstelle keine Methoden implementieren kann. Sie ist nur eine Liste der Methodenprototypen. Der
zweite Unterschied ist, dass man in einer Klasse beliebing viele Schnittstellen implementieren kann.
Technisch, wird beim Kopf einer Schnittstelle statt „class“ das Wort „interface“ benutzt, und zwar
werden die zur einen Klasse zugehörende Schnittstellen nach dem Schlüßelwort „implements“ statt
nach „extends“ geschrieben. Der Namenseparator is Komma. All das sieht so aus:
public class Unterklasse
extends Oberklasse
implements Schnittstelle1, Schnittstelle2, Schnittstelle3 // usw.
{
19
Autor: M. A.
10.1
In unserem Fall brauchen wir eine Liste der Methoden, die uns beim Zeichnen auf einem Applet
dienen werden. Da braucht man zurzeit nichts mehr als eine Methode: public void zeichnen(Graphics) .
Dateiname der Schnittstelle wird ZObjekt.java sein.
package geometrie;
import java.awt.*;
public interface ZObjekt {
public void zeichnen(Graphics g);
}
Nun können wir diese Schnittstelle zur Basisklasse implementieren. Es genügt den Kopf der
Klasse nach „public abstract class GObjekt implements ZObjekt { “ zu ändern. Diese Methode können Sie entweder für alle Unterklassen der Klasse GObjekt implementieren oder diese
Arbeit verkürzern. Da jede Unterklasse ihre px und py in Betracht zieht, ist das eine wiederholende
Aufgabe, die die Basisklasse schaffen kann. Das Gleiche gilt für Initialisierung der Graphics g für
GPrim. Also die Methode zeichen(Graphics g) wird nur in der Klasse GObject implementiert. Zur
Klasse GObject werden wir eine neue Methode protected abstract void internesZeichnen()
einfügen, die in den Unterklassen implementiert wird. Sie wird in der Methode zeichnen(Graphics)
gerufen. Die Neuigkeiten werden so aussehen:
import java.awt.*;
public abstract class GObjekt implements ZObjekt {
// ...
protected abstract void internesZeichnen();
public void zeichnen(Graphics g) {
GPrim.setG(g);
GPrim.translateTo(px, py);
internesZeichnen();
}
}
Nun sollen sie die Methode internesZeichnen für alle Unterklassen implementieren. Dank der
Klasse GPrim, sollte das nun eine leichte Aufgabe sein. Zum Beispiel würde sie für die Ellipse so
lauten:
protected void internesZeichnen() {
GPrim.ellipse(a, b);
}
Für Punkt:
protected void internesZeichnen() {
GPrim.punkt(x, y);
}
Für Dreieck:
protected void internesZeichnen() {
GPrim.vieleck(a, b, c);
}
Versuchen Sie die andere Methoden selbst zu schreiben. Diese Methoden sind von äußeren Klassen versteckt, da ihre Funktionsweise stark von der internen (dem Benutzer unbekannten) Architektur
abhängt.
20
11
Applet
Nun können wir schon einen Applet schreiben und da diese Objekte zeichnen. Dies werden wir aber
nicht in Paket geometrie machen, sondern in default Paket. Machen Sie dort einen neuen Applet
mit dem Namen Demo.java und importieren Sie unter anderem das Paket geometrie.*;. Machen
Sie eine neue Reihe private ZObjekt[] arr = {null, null, null}; als Attribut der Klasse.
Diese Reihe wird bald mit drei verschiedenen geometrischen Objekte ausgefüllt werden.
Man kann in jedem Applet seine eigene Methode public void init() implementieren, die zur
Initialisierung vor dem Zeichnen dient. Also wir werden unsere drei Objekte dort machen. Merken Sie
sich, dass ein Zeiger vom Typ ZObjekt jedes Objekt der Klasse GObjekt aufnehmen kann. Jedoch,
kann man so nur die Methode zeichnen(Graphics) zurzeit rufen.
public void init() {
arr[0] = new Punkt(3,3);
arr[1] = new Dreieck().positionieren(4,4);
arr[2] = new Ellipse(2,1).positionieren(3,2);
}
Mit der Methode paint() kann man nun Zeichnen implementieren. Dabei wird bei jedem Element
von arr kontrolliert, ob es nur ein null-Zeiger ist.
public void paint(Graphics g) {
for(int i=0; i < arr.length; i++) {
if(arr[i] != null) {
arr[i].zeichnen(g);
}
}
}
Nun ist auch das richtige Moment, foreach17 (von engl. für jedes) Anweisung in Java zu erwähnen.
Sie kann man jedes Mal benutzen, wenn kein Gebrauch entsteht, auf die Indexe aufzupassen. Die
obere for Schleife würde als foreach so aussehen:
for(ZObjekt obj : arr) {
if(obj != null) {
obj.zeichnen(g);
}
}
In Java wird foreach durch das Schlüßelwort for aufgerufen. Das erste Argument (ZObjekt obj)
sind der Typ und der Name eines Objekts zur Verarbeitung. Das zweite Argument (arr) ist der
Name eines Objektcontainers. Das kann entweder ein Objekt sein, dessen Typ die Schnittstelle
Iterable implementiert (ArrayList zum Beispiel), ode eine Reihe. Diese Argumenten sind mit
einem Doppelpunkt getrennt.
17
http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html
21
Herunterladen