Geometrische Figuren
Lösung geprüft
Die Aufgabe der heutigen Stunde sind die geometrischen Figuren! Quadrat, Rechteck, Kreis und am Ende noch ein rechtwinkliges Dreieck sollen objektorientiert modelliert werden. Das ist die erste Aufgabe, bei der wir mehrere Klassen nebeneinander haben, die sich sehr ähnlich sind – und genau da fängt OOP an, sich zu lohnen.
Die Aufgabe hat vier Teile plus Zusatzaufgaben. Teil b) ist eine reine Textaufgabe, die wird gerne überlesen – die ist aber die, die in der Klausur drankommt.
a) Erstellen Sie einen Ordner
geometrischeobjekte. Speichern Sie die Datei
Quadrat.java in dem Ordner ab. Führen Sie die Datei aus.
Schreiben Sie eine Klasse Spielwiese und testen Sie die
Klasse Quadrat.
b) Beschreiben und erklären Sie den Code. Verwenden Sie Fachsprache. Tipp: Bauen Sie die folgenden Vokabeln in ihren Antworttext ein: Klasse, Attribut, Methode, Parameter bzw. Argumente, Datentyp, Rückgabewert, Konkatenation, lokale Variable, Dezimalzahl, …
c) Programmieren Sie die Klassen
Rechteck, Kreis (Math.PI),
erstellen Sie Objekte und schreiben Sie eine Ausgabe. Die Angabe der
Längen erfolgt in cm. Halten Sie das EVA-Prinzip in der
Ausgabemethode ein, d.h. den Ausgabe-String konkatenieren und am
Ende ausgeben.
d) Erweitern Sie die Klassen um ein rechtwinkliges
Dreieck RechtwinkligesDreieck.java. Die Parameter sind
die Katheten. Tipp: Pythagoras: Kathete mal Kathete ist die
Hypotenuse im Quadrat: Math.sqrt(a * a + b * b);
Zusatz: Erweitern Sie die Klasse
RechtwinkligesDreieck, damit auch Kathete und
Hypotenuse eingegeben werden können. Verwenden Sie einen dritten
boolean-Parameter, damit dies möglich wird.
Was vorgegeben ist
Die Klasse Quadrat bekommst du fertig. Sie ist die Vorlage
für alles, was danach kommt – schau sie dir genau an, die anderen drei
Klassen sind nach demselben Muster gebaut.
public class Quadrat {
private double seitenlaenge;
public Quadrat(double seitenlaenge) {
this.seitenlaenge = seitenlaenge;
}
public double berechneFlaeche() {
return seitenlaenge * seitenlaenge;
}
public double berechneUmfang() {
return 4 * seitenlaenge;
}
public double getSeitenlaenge() {
return seitenlaenge;
}
public void setSeitenlaenge(double seitenlaenge) {
this.seitenlaenge = seitenlaenge;
}
public void print() {
String ausgabe = "Quadrat mit Seitenlänge = " + seitenlaenge + " cm\n" +
"Fläche = " + berechneFlaeche() + " cm²\n" +
"Umfang = " + berechneUmfang() + " cm";
System.out.println(ausgabe);
}
}
Lösungsprozess der Aufgabe
/**
*
* Die geometrischen Figuren - alle vier Klassen plus Spielwiese
* Jede Klasse gehoert in eine eigene .java-Datei im Ordner geometrischeobjekte
*
* @version 1.0 vom 17.02.2021
* @meininfokurs.cmrg.site
*/
// ============ Rechteck.java ============
public class Rechteck {
private double breite;
private double hoehe;
public Rechteck(double breite, double hoehe) {
this.breite = breite;
this.hoehe = hoehe;
}
public double berechneFlaeche() {
return breite * hoehe;
}
public double berechneUmfang() {
return 2 * breite + 2 * hoehe;
}
public double getBreite() {
return breite;
}
public double getHoehe() {
return hoehe;
}
public void setBreite(double breite) {
this.breite = breite;
}
public void setHoehe(double hoehe) {
this.hoehe = hoehe;
}
public void print() {
String ausgabe = "Rechteck mit Breite = " + breite + " cm und Hoehe = " + hoehe + " cm\n" +
"Fläche = " + berechneFlaeche() + " cm²\n" +
"Umfang = " + berechneUmfang() + " cm";
System.out.println(ausgabe);
}
}
// ============ Kreis.java ============
public class Kreis {
private double radius;
public Kreis(double radius) {
this.radius = radius;
}
public double berechneFlaeche() {
return Math.PI * radius * radius;
}
public double berechneUmfang() {
return 2 * Math.PI * radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public void print() {
String ausgabe = "Kreis mit Radius = " + radius + " cm\n" +
"Fläche = " + berechneFlaeche() + " cm²\n" +
"Umfang = " + berechneUmfang() + " cm";
System.out.println(ausgabe);
}
}
// ============ RechtwinkligesDreieck.java ============
public class RechtwinkligesDreieck {
private double katheteA;
private double katheteB;
// Konstruktor 1: beide Katheten sind bekannt
public RechtwinkligesDreieck(double katheteA, double katheteB) {
this.katheteA = katheteA;
this.katheteB = katheteB;
}
// Zusatzaufgabe - Konstruktor 2: eine Kathete und die Hypotenuse.
// Der boolean sagt, wie der zweite Wert gemeint ist.
public RechtwinkligesDreieck(double katheteA, double zweiterWert, boolean istHypotenuse) {
this.katheteA = katheteA;
if (istHypotenuse) {
this.katheteB = Math.sqrt(zweiterWert * zweiterWert - katheteA * katheteA);
} else {
this.katheteB = zweiterWert;
}
}
public double berechneHypotenuse() {
return Math.sqrt(katheteA * katheteA + katheteB * katheteB);
}
public double berechneFlaeche() {
return katheteA * katheteB / 2;
}
public double berechneUmfang() {
return katheteA + katheteB + berechneHypotenuse();
}
public double getKatheteA() {
return katheteA;
}
public double getKatheteB() {
return katheteB;
}
public void print() {
String ausgabe = "Rechtwinkliges Dreieck mit Katheten " + katheteA + " cm und " + katheteB + " cm\n" +
"Hypotenuse = " + berechneHypotenuse() + " cm\n" +
"Fläche = " + berechneFlaeche() + " cm²\n" +
"Umfang = " + berechneUmfang() + " cm";
System.out.println(ausgabe);
}
}
// ============ Spielwiese.java ============
public class Spielwiese {
public static void main(String[] args) {
Quadrat q = new Quadrat(5);
q.print();
System.out.println("");
Rechteck r = new Rechteck(4, 7);
r.print();
System.out.println("");
Kreis k = new Kreis(3);
k.print();
System.out.println("");
RechtwinkligesDreieck d = new RechtwinkligesDreieck(3, 4);
d.print();
System.out.println("");
// Zusatz: 3 cm Kathete, 5 cm Hypotenuse -> die andere Kathete ist 4
RechtwinkligesDreieck d2 = new RechtwinkligesDreieck(3, 5, true);
d2.print();
} // end of main
} // end of class Spielwiese
In der Aufgabenstellung wird gefordert, dass wir folgende Sachen umsetzen:
- Eine Klasse
Spielwiesezum Testen schreiben - Den vorgegebenen Quadrat-Code mit Fachsprache erklären
RechteckundKreisnach demselben Muster bauen- In der Ausgabemethode das EVA-Prinzip einhalten
RechtwinkligesDreieckmit Pythagoras ergänzen- Zusatz: zweiter Konstruktor mit
boolean-Parameter
Teil b) – den Code mit Fachsprache erklären
Hier will der Lehrer hören, dass du die Vokabeln richtig benutzt. Am
Beispiel von Quadrat durchgegangen:
| Im Code | Fachbegriff |
|---|---|
public class Quadrat | Die Klasse – der Bauplan für alle Quadrate |
private double seitenlaenge; | Ein Attribut vom Datentyp double, also eine Dezimalzahl |
Quadrat(double seitenlaenge) | Der Konstruktor; seitenlaenge ist sein Parameter |
new Quadrat(5) | Beim Aufruf ist die 5 das Argument |
berechneFlaeche() | Eine Methode mit Rückgabewert double, also eine Funktion |
print() | Eine Methode ohne Rückgabewert (void), also eine Prozedur |
String ausgabe = … | Eine lokale Variable – lebt nur innerhalb von print() |
"Fläche = " + berechneFlaeche() | Konkatenation: Text und Zahl werden aneinandergehängt |
Der Unterschied zwischen Parameter und Argument wird gern durcheinandergebracht: der Parameter steht in der Klammer, wenn du die Methode schreibst. Das Argument ist der konkrete Wert, den du beim Aufrufen reinsteckst. Parameter ist die Vorlage, Argument ist das Eingesetzte.
Und der Unterschied zwischen Attribut und lokaler Variable: das
Attribut seitenlaenge gehört zum Objekt und lebt so lange
wie das Objekt. Die lokale Variable ausgabe entsteht beim
Aufruf von print() und ist danach wieder weg.
Rechteck und Kreis: dasselbe Muster
Wenn du das Quadrat verstanden hast, sind die beiden eigentlich nur
Fleißarbeit. Jede Klasse hat ihre Attribute, einen Konstruktor,
berechneFlaeche(), berechneUmfang(), Getter
und print(). Nur die Formeln ändern sich:
| Figur | Fläche | Umfang |
|---|---|---|
| Quadrat | a * a | 4 * a |
| Rechteck | breite * hoehe | 2 * breite + 2 * hoehe |
| Kreis | Math.PI * r * r | 2 * Math.PI * r |
| Dreieck | a * b / 2 | a + b + Hypotenuse |
Math.PI ist eine Konstante aus der Java-Bibliothek, die
brauchst du nicht selbst zu definieren. Schreib bloß nicht
3.14 hin, das ist zu ungenau und der Lehrer sieht es
sofort.
Dass alle vier Klassen fast gleich aussehen, ist übrigens kein Zufall
und auch kein Fehler – aber es ist genau der Punkt, an dem man später
mit Vererbung ansetzt. Da hätte man eine Oberklasse Figur
und die vier erben davon. Hatten wir noch nicht, deshalb schreiben wir
es hier viermal hin.
Das Dreieck und Pythagoras
Beim rechtwinkligen Dreieck kennen wir nur die beiden Katheten. Die Hypotenuse müssen wir ausrechnen, und dafür ist der Satz des Pythagoras da:
public double berechneHypotenuse() {
return Math.sqrt(katheteA * katheteA + katheteB * katheteB);
}
Wichtig: das ist eine Methode und kein Attribut. Die Hypotenuse wird bei jedem Aufruf frisch berechnet. Würden wir sie als Attribut speichern, müssten wir sie bei jeder Änderung einer Kathete nachziehen – und genau das vergisst man dann. Als Methode kann sie gar nicht veralten.
Denselben Trick nutzt berechneUmfang(): die ruft einfach
berechneHypotenuse() mit auf. Methoden dürfen andere
Methoden derselben Klasse benutzen, ohne Punkt davor.
Die Zusatzaufgabe mit dem boolean
Jetzt wird es interessant. Es soll auch möglich sein, eine Kathete und
die Hypotenuse anzugeben. Das Problem: ein zweiter Konstruktor mit
(double, double) geht nicht – den gibt es schon, und Java
unterscheidet Konstruktoren nur an der Parameterliste. Deshalb kommt ein
dritter Parameter dazu, der sagt, wie der zweite Wert gemeint ist:
public RechtwinkligesDreieck(double katheteA, double zweiterWert, boolean istHypotenuse) {
this.katheteA = katheteA;
if (istHypotenuse) {
this.katheteB = Math.sqrt(zweiterWert * zweiterWert - katheteA * katheteA);
} else {
this.katheteB = zweiterWert;
}
}
Beachte das Minus in der Wurzel. Vorher haben wir die Hypotenuse aus den Katheten gerechnet, da wurde addiert. Jetzt gehen wir rückwärts und ziehen ab: c² − a² = b². Wer hier aus Versehen ein Plus tippt, bekommt ein Dreieck, das aussieht als wäre alles in Ordnung – die Zahlen sind nur falsch.
Das ist auch schon Konstruktor-Überladung, also genau das Thema der nächsten Aufgabe. Zwei Konstruktoren in derselben Klasse, unterschieden an der Parameterliste.
Und so sieht die Ausgabe aus
Quadrat mit Seitenlänge = 5.0 cm
Fläche = 25.0 cm²
Umfang = 20.0 cm
Rechteck mit Breite = 4.0 cm und Hoehe = 7.0 cm
Fläche = 28.0 cm²
Umfang = 22.0 cm
Kreis mit Radius = 3.0 cm
Fläche = 28.274333882308138 cm²
Umfang = 18.84955592153876 cm
Rechtwinkliges Dreieck mit Katheten 3.0 cm und 4.0 cm
Hypotenuse = 5.0 cm
Fläche = 6.0 cm²
Umfang = 12.0 cm
Rechtwinkliges Dreieck mit Katheten 3.0 cm und 4.0 cm
Hypotenuse = 5.0 cm
Fläche = 6.0 cm²
Umfang = 12.0 cm
Die beiden Dreiecke am Ende sind absichtlich identisch – einmal aus zwei Katheten (3, 4) gebaut, einmal aus Kathete 3 und Hypotenuse 5. Das ist der schnellste Test, ob dein zweiter Konstruktor richtig rechnet. Das 3-4-5-Dreieck ist dafür perfekt, weil da lauter glatte Zahlen rauskommen.
Die krummen Zahlen beim Kreis stören übrigens niemanden, die sind
mathematisch korrekt. Wenn du sie schöner haben willst, pack
InOut.format2(...) drumherum – gefordert ist es hier
nicht.
*** markierten Zusatzaufgaben (GUI mit
dem Java-Editor und die Turtle-Zeichnung) sind hier nicht dabei – die
gehören zum GUI-Teil und haben mit den Figuren selbst nichts mehr zu
tun.