Aufgabenblock — AFB II
Zehn mehrschrittige Aufgaben, bunt gemischt aus allen Unterkapiteln: Klassendiagramme aus Texten erstellen, Klassen mit Assoziationen und Vererbung implementieren, Aufrufe mit Referenzen und überschriebenen Methoden verfolgen und Fehler im Quelltext erklären. 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: Bis zu 15 Minuten Parkdauer ist das Parken kostenlos. Wird länger geparkt, kostet jede angefangene halbe Stunde der gesamten Parkdauer 150 Cent, 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.
Ein Mobilfunkanbieter modelliert seine Tarife mit Vererbung. Die Klasse Tarif hat das geschützte Attribut grundgebuehr (#); Tarif.kosten(minuten) liefert grundgebuehr + minuten * 0.09.
public class Flatrate extends Tarif {
public Flatrate(String name, double grundgebuehr) { super(name, grundgebuehr); }
@Override
public double kosten(int minuten) { return grundgebuehr; }
}
public class Kombi extends Tarif {
private int freiminuten;
public Kombi(String name, double g, int freiminuten) { super(name, g); this.freiminuten = freiminuten; }
@Override
public double kosten(int minuten) {
if (minuten <= freiminuten) { return grundgebuehr; }
return super.kosten(minuten - freiminuten);
}
}ArrayList<Tarif> t = new ArrayList<Tarif>();
t.add(new Tarif("Basis", 5.00));
t.add(new Flatrate("Flat", 19.99));
t.add(new Kombi("Kombi", 9.99, 100));
double s = 0;
for (int i = 0; i < t.size(); i++) {
s = s + t.get(i).kosten(300);
}Analysieren Sie den Ablauf und geben Sie die Werte in Euro an.
kosten-Methode.super.kosten(200) mit der Formel aus Tarif — aber mit der Grundgebühr dieses Objekts.Vollständige Lösung
Basis: 5,00 + 27,00 = 32,00 €. Flat: 19,99 € (überschrieben, unabhängig von den Minuten). Kombi: 300 > 100, also super.kosten(200) = 9,99 + 200 · 0,09 = 27,99 €. Summe 79,98 €. Bei 80 Minuten liegt der Kombi-Tarif innerhalb der Freiminuten: 9,99 €.
Die Schleife kennt nur den Typ Tarif — dass drei verschiedene Methoden laufen, liegt an der dynamischen Bindung.
