MV Abitur Computer Science study materials
MV Abitur Computer Science study resources

Bibliothekssoftware: Wenn die Unterklasse das Versprechen bricht

MV Abitur Computer Science · Put your knowledge to work in context.

All case studies

Bibliothekssoftware: Wenn die Unterklasse das Versprechen bricht

Für die Schulbibliothek entsteht ein Java-Programm. Die Klasse Medium besitzt die Methoden ausleihen(int tage) und gebuehr(int tage); davon leiten die Schülerinnen und Schüler Buch, DVD und EBook ab. EBook erbt ebenfalls von Medium, weil ein E-Book „auch ein Medium ist“, doch ausleihen wirft dort eine UnsupportedOperationException, da E-Books nicht verliehen, sondern nur online gelesen werden. Die Ausleihschleife for (Medium m : bestand) { m.ausleihen(7); } bricht deshalb nach 1.200 der 3.400 Medien ab, sobald das erste E-Book an die Reihe kommt. Zusätzlich überschreibt DVD die Methode gebuehr: Für 1–3 Tage werden 2,00 € berechnet, ab 4 Tagen 0 € („Wochenendtarif“). Damit ist eine 7-Tage-Ausleihe günstiger als eine 3-Tage-Ausleihe, und die Monatsstatistik weist für DVDs deutlich weniger Einnahmen aus als erwartet. Die Lehrkraft besteht auf einer sauberen Modellierung, bevor die Projektnote vergeben wird.

1. Begründen Sie formal, warum die Klasse `EBook` das Liskovsche Substitutionsprinzip verletzt. Welche Annahmen des aufrufenden Codes brechen?

Read the worked answer

Vertrag der Oberklasse: ausleihen(int tage) hat die Vorbedingung tage > 0 und die Nachbedingung „das Medium ist als ausgeliehen markiert, die Methode kehrt normal zurück“. Jeder Aufrufer darf sich darauf verlassen, wenn er eine Variable vom Typ Medium in der Hand hat.

Verletzung: EBook verschärft die Vorbedingung faktisch auf „niemals“ und ersetzt die Nachbedingung durch eine Ausnahme. Das LSP verlangt, dass ein Subtyp schwächere Vorbedingungen und stärkere Nachbedingungen hat – also mehr Aufrufe akzeptiert und mehr garantiert, nie weniger. Hier ist es umgekehrt.

Was im Client bricht:

  1. Die Schleife über List<Medium> geht davon aus, dass jedes Element ausleihbar ist. Der Typ Medium verspricht das – der Laufzeitabbruch zeigt, dass das Versprechen falsch war.
  2. Die Typprüfung des Compilers wird wertlos: Der Code kompiliert sauber und fällt erst in der Produktion um.
  3. Um den Fehler zu beheben, müsste der Client instanceof EBook prüfen. Damit kennt der Client alle Unterklassen; jede neue nicht-ausleihbare Mediengattung erfordert eine Änderung an zentraler Stelle – ein Verstoß gegen das Open-Closed-Prinzip.
  4. Die Ausnahme ist hier auch kein Ausnahmefall, sondern der Normalfall für eine ganze Klasse von Objekten. Ausnahmen sind für unerwartete Situationen gedacht, nicht für reguläre Zustände.

Kurz: Nicht „E-Book ist ein Medium“ ist das Problem, sondern dass Medium eine Fähigkeit enthält, die nicht alle Medien besitzen. Die Vererbung wurde nach dem Fachwort (is-a) statt nach dem Verhalten geschnitten.

2. Entwerfen Sie eine alternative Modellierung ohne Verletzung des LSP. Beschreiben Sie Klassen, Schnittstellen und Beziehungen sowie die Anpassung der Ausleihschleife.

Read the worked answer

Struktur (in Worten statt als Diagramm):

  • Schnittstelle Ausleihbar mit ausleihen(int tage) und zurueckgeben().
  • Abstrakte Klasse Medium mit titel, signatur und abstract double gebuehr(int tage) – aber ohne ausleihen.
  • Buch extends Medium implements Ausleihbar.
  • DVD extends Medium implements Ausleihbar.
  • EBook extends Medium (ohne Ausleihbar) mit oeffneOnline().
  • Schnittstelle Tarif mit double preis(int tage); StandardTarif und WochenendTarif implementieren sie. DVD bekommt ein Tarif-Objekt über den Konstruktor (Strategie-Muster).

Beziehungen: Vererbung nur für „echte“ Gemeinsamkeiten (Titel, Signatur, Gebührenberechnung), Fähigkeiten über Schnittstellen, variierendes Verhalten über Komposition. Das ist der Wechsel von Vererbung zu Komposition, wo Vererbung nur der Wiederverwendung diente.

Angepasste Schleife:

List<Ausleihbar> ausleihbar = new ArrayList<>();
// nur Buch und DVD werden eingefügt
for (Ausleihbar m : ausleihbar) { m.ausleihen(7); }

Der Typ macht jetzt genau die Zusage, die gehalten wird. E-Books können gar nicht erst in die Liste gelangen – der Fehler wird vom Laufzeit- zum Compilezeitfehler, und das ist ein Gewinn.

Nebeneffekt: Die Gebührenlogik ist austauschbar und einzeln testbar; ein neuer Tarif erfordert keine Änderung an DVD.

Grenze der Lösung: Soll ein Medium sowohl ausleihbar als auch online lesbar sein (Hybrid), kombiniert es beide Schnittstellen – auch das bleibt ohne Vererbungskonflikt möglich.

3. Bewerten Sie die Tarifregel der Klasse `DVD` (0 € ab 4 Tagen): Ist das ein LSP-Problem, ein Fachproblem oder beides? Begründen Sie und schlagen Sie eine Absicherung vor.

Read the worked answer

Zunächst: kein formaler LSP-Verstoß. Signatur, Rückgabetyp und Vorbedingung bleiben gleich; es wird keine Ausnahme geworfen. Ein LSP-Verstoß im engeren Sinn liegt nicht vor.

Aber: Verstoß gegen eine implizite Nachbedingung. Der Methodenname gebuehr und die Dokumentation der Oberklasse legen nahe, dass die Gebühr mit der Ausleihdauer nicht sinkt (Monotonie) und nicht negativ wird. Diese Annahme ist nirgends aufgeschrieben, wird aber von der Statistik und vom Mahnwesen geteilt – sonst wäre die Abweichung nicht aufgefallen. Ein Subtyp darf Verhalten präzisieren, aber nicht stillschweigend die Bedeutung einer geerbten Methode umkehren; das ist ein Vertragsbruch im weiteren Sinn, weil Zusicherungen außerhalb des Codes liegen und niemand sie prüfen kann.

Zusätzlich ein Fachproblem: Eine 7-Tage-Ausleihe für 0 € ist wirtschaftlich unsinnig und lädt zum Ausnutzen ein. Wer drei Tage bucht und nach Ablauf einfach wartet, zahlt mehr als jemand, der von Anfang an sieben Tage bucht. Die Regel ist also nicht nur technisch riskant, sondern fachlich falsch – vermutlich war ein Wochenendtarif (Fr–Mo) gemeint, nicht „ab 4 Tagen gratis“.

Absicherung:

  1. Vertrag explizit dokumentieren (Javadoc: „Gebühr ist monoton nicht fallend in tage, ≥ 0“) und in der Oberklasse als Zusicherung festhalten.
  2. Tarifregeln in eigene Tarif-Objekte auslagern, die gegen den Vertrag getestet werden (Property-Test: gebuehr(7) >= gebuehr(3)).
  3. Fachliche Klärung vor der Implementierung: Wenn ein Sondertarif gewollt ist, bekommt er einen eigenen Namen (wochenendTarif), statt gebuehr zu überschreiben.
  4. Statistik und Mahnwesen nicht auf ungeschriebene Annahmen bauen, sondern auf dokumentierte Kennzahlen.