Aufgabenblock — AFB II
Zehn mehrschrittige Aufgaben, bunt gemischt aus allen Unterkapiteln: Klassendiagramme aus Texten erstellen, Klassen und Methoden mit Schleifen implementieren, Aufrufe mit Referenzen und Aliasen verfolgen, Reihungen von Objekten auswerten und Fehler im Quelltext finden. Die gestuften Tipps helfen, wenn du nicht weiterkommst.
Eine Stadtbibliothek beschreibt ihre Anforderungen so:
„Jedes Medium hat eine Signatur und einen Titel; beides ändert sich nach dem Erfassen nicht mehr. Man muss abfragen können, ob ein Medium ausgeliehen ist und von wem. Ein Leser hat eine Ausweisnummer und einen Namen. Er darf höchstens fünf Medien gleichzeitig ausleihen. Ein Leser kann ein Medium ausleihen und zurückgeben; außerdem soll man abfragen können, wie viele Medien er gerade hat.“
Erstellen Sie ein Klassendiagramm mit den Klassen Medium und Leser (Attribute, Konstruktoren, Methoden, Assoziation mit Kardinalitäten).
null). „höchstens fünf Medien“ spricht für eine Reihung vom Typ Medium mit Länge 5 und einen Zähler.Vollständige Lösung
- - ausweisNr: Ganzzahl
- - name: Zeichenkette
- - medien: Reihung vom Typ Medium
- - anzahl: Ganzzahl
- c Leser(ausweisNr: Ganzzahl, name: Zeichenkette)
- + ausleihen(m: Medium): Wahrheitswert
- + zurueckgeben(m: Medium)
- + getAnzahl(): Ganzzahl
- - signatur: Zeichenkette
- - titel: Zeichenkette
- - ausleiher: Leser
- c Medium(signatur: Zeichenkette, titel: Zeichenkette)
- + getSignatur(): Zeichenkette
- + getTitel(): Zeichenkette
- + istAusgeliehen(): Wahrheitswert
- + getAusleiher(): Leser
- + setAusleiher(l: Leser)
Begründungen: Signatur und Titel bekommen keinen Setter (nur lesbar). „Ausgeliehen“ braucht kein eigenes Attribut: istAusgeliehen() liefert ausleiher != null — so können die beiden Angaben nie widersprüchlich werden. ausleihen liefert einen Wahrheitswert, weil es scheitern kann (schon fünf Medien oder Medium schon verliehen). Ein Medium ist bei höchstens einem Leser (0..1), ein Leser hat 0 bis 5 Medien.
So könnte Leser implementiert werden:
public class Leser {
private int ausweisNr;
private String name;
private Medium[] medien;
private int anzahl;
public Leser(int ausweisNr, String name) {
this.ausweisNr = ausweisNr;
this.name = name;
medien = new Medium[5];
anzahl = 0;
}
public boolean ausleihen(Medium m) {
if (anzahl < medien.length && !m.istAusgeliehen()) {
medien[anzahl] = m;
anzahl = anzahl + 1;
m.setAusleiher(this);
return true;
}
return false;
}
public void zurueckgeben(Medium m) {
for (int i = 0; i < anzahl; i++) {
if (medien[i] == m) {
medien[i] = medien[anzahl - 1];
medien[anzahl - 1] = null;
anzahl = anzahl - 1;
m.setAusleiher(null);
return;
}
}
}
public int getAnzahl() {
return anzahl;
}
}
Ein Parkhaus rechnet so ab: Die ersten 15 Minuten sind kostenlos. Wer länger parkt, zahlt für die gesamte Parkdauer 150 Cent je angefangene halbe Stunde, höchstens aber 1200 Cent. Zeiten werden in Minuten seit Mitternacht gespeichert (8:40 Uhr = 520).
- - einfahrt: Ganzzahl
- - bezahlt: Wahrheitswert
- c Parkticket(einfahrt: Ganzzahl)
- + getEinfahrt(): Ganzzahl
- + berechneGebuehr(ausfahrt: Ganzzahl): Ganzzahl
- + bezahlen()
- + istBezahlt(): Wahrheitswert
Implementieren Sie die Klasse. Ermitteln Sie außerdem die Gebühr in Cent für ein Ticket mit Einfahrt 8:40 Uhr bei Ausfahrt um 10:15 Uhr bzw. um 16:40 Uhr.
berechneGebuehr zuerst die Parkdauer ausfahrt − einfahrt bestimmen, dann die drei Regeln nacheinander anwenden.dauer / 30 ab. Der Trick (dauer + 29) / 30 rundet auf: 95 Minuten → 124 / 30 = 4 Takte.Vollständige Lösung
public class Parkticket {
private int einfahrt;
private boolean bezahlt;
public Parkticket(int einfahrt) {
this.einfahrt = einfahrt;
bezahlt = false;
}
public int getEinfahrt() {
return einfahrt;
}
public int berechneGebuehr(int ausfahrt) {
int dauer = ausfahrt - einfahrt;
if (dauer <= 15) {
return 0;
}
int takte = (dauer + 29) / 30;
int gebuehr = takte * 150;
if (gebuehr > 1200) {
gebuehr = 1200;
}
return gebuehr;
}
public void bezahlen() {
bezahlt = true;
}
public boolean istBezahlt() {
return bezahlt;
}
}
10:15 Uhr: Dauer 615 − 520 = 95 min → 4 angefangene halbe Stunden → 4 · 150 = 600 Cent.
16:40 Uhr: Dauer 480 min → 16 Takte → 2400 Cent, gedeckelt auf 1200 Cent.
Wer mit dauer / 30 rechnet, erhält fälschlich 3 Takte (450 Cent). Einen Setter für einfahrt gibt es bewusst nicht — die Einfahrtszeit darf nachträglich nicht manipulierbar sein.
In der Mitgliederverwaltung eines Sportvereins senkt ermaessigen(prozent) den Jahresbeitrag (in Euro) mit der Anweisung beitrag = beitrag - beitrag * prozent / 100;
Mitglied a = new Mitglied("Ole", 120);
Mitglied b = new Mitglied("Ole", 120);
Mitglied c = a;
c.ermaessigen(25);
b = c;
b.ermaessigen(10);
int x = a.getBeitrag();
x = x - 1;
boolean gleich = (a == b);
Stellen Sie den Ablauf in einer Tracetabelle dar (Variablen und Objektzustände) und geben Sie die Endwerte an. Wie viele Mitglied-Objekte werden erzeugt, und welchen Wert hat gleich?
a, b, c jeweils, auf welches Objekt sie zeigen.b = c kopiert die Referenz. Danach zeigen alle drei Variablen auf Objekt 1; Objekt 2 ist nicht mehr erreichbar.Vollständige Lösung
Mitglied a = new Mitglied("Ole", 120); // a -> O1 (120)
Mitglied b = new Mitglied("Ole", 120); // b -> O2 (120)
Mitglied c = a; // c -> O1
c.ermaessigen(25); // O1: 90
b = c; // b -> O1, O2 unerreichbar
b.ermaessigen(10); // O1: 81
int x = a.getBeitrag(); // x = 81 (Kopie des Werts)
x = x - 1; // x = 80, O1 bleibt 81
boolean gleich = (a == b); // true: gleiche Referenz
Endwerte: a.getBeitrag() = 81, x = 80, es wurden 2 Objekte erzeugt, gleich ist true. Hätte man a == b direkt nach Zeile 2 geprüft, wäre das Ergebnis false gewesen — trotz gleicher Attributwerte.
