Übungsaufgaben zu Polymorphie und später Bindung

https://bildung.social/@oerinformatik/

https://oer-informatik.de/uml-klassendiagramm-polymorphie-uebungsaufgaben

Polymorphie, Späte Bindung, UML-Klassendiagramm, Abstrakte Klasse, Überschreiben, Überladen, Zustandsmuster, Vererbung, Übungsaufgaben, Prüfungsvorbereitung

tl/dr; (Bearbeitungszeit insgesamt 56 min, mehrere Aufgaben): Zwei Übungsaufgaben auf Profilkompetenz-Ebene: Du findest den Fehler einer Fallunterscheidung über ein Typattribut, korrigierst einen fehlerhaften polymorphen Klassenentwurf, sagst die Ausgabe polymorpher Aufrufe voraus, beurteilst überschreibende Methoden mit super, prüfst Zuweisungen zwischen Referenztypen und erklärst die späte Bindung am Zustand-Entwurfsmuster [AI-Assisted]. (Zuletzt geändert am 29.10.2026)

Dieser Artikel ist Teil einer Artikelreihe über UML-Klassendiagramme: Einstieg in das Klassendiagramm (Übung Ticketautomat, Übungsaufgaben) / Sichtbarkeitsmodifikatoren / Assoziation, Aggregation, Komposition (Übungsaufgaben) / Vererbung (Übungsaufgaben) / Abstrakte Klassen und Interfaces / Polymorphie (Übungsaufgaben). Dazu: Klassendiagramme mit PlantUML zeichnen und Objektdiagramm.

Diese Übungsaufgaben gehören zum Artikel Polymorphie in der objektorientierten Programmierung. Sie setzen die Inhalte der Artikel Klassenbeziehungen: Vererbung und abstrakte Klassen und Interfaces voraus. Weitere Übungen zum Zustand- und Strategiemuster findest Du unter Übungsaufgaben zu Entwurfsmustern.

Wortwolke mit den zentralen Begriffen der Übungsaufgaben zu Polymorphie und später Bindung (mit KI erstellt)

Hinweise zur Bearbeitung: Von FIA wird erwartet, dass ihnen Aufgaben auf Profilkompetenz-Ebene (Aufgabe 3.1 und Aufgabe 3.2) keine Probleme bereiten. Bearbeite die Teilaufgaben zunächst ohne Hilfsmittel auf Papier (Faustregel: ein Punkt entspricht etwa einer Minute). Pseudocode darf sich an Java, C# oder Python anlehnen, solange der objektorientierte Aufruf (objekt.methode()) erkennbar ist. Die Lösungen kannst Du unter jeder Teilaufgabe einblenden. Die Punkteverteilung zeigt, worauf es bei der Bewertung ankommt; andere fachlich richtige Lösungen sind ebenfalls möglich.

Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?

Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.

Erstelle neue Übungsaufgaben zum Thema „Polymorphie und später Bindung“.

Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.

Fachliche Grundlage:
- https://oer-informatik.de/uml-klassendiagramm-polymorphie
- https://oer-informatik.de/uml-klassendiagramm-vererbung
- https://oer-informatik.de/uml-klassendiagramm-interface-abstraktion
- https://oer-informatik.de/entwurfsmuster
- Stilbeispiel: https://oer-informatik.de/uml-klassendiagramm-polymorphie-uebungsaufgaben

Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Polymorphie
- Späte Bindung
- UML-Klassendiagramm
- Abstrakte Klasse
- Überschreiben
- Überladen
- Zustandsmuster
- Vererbung

Kompetenzstufe: Profilkompetenz (alternativ: Basiskompetenz, Kernkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan

Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
   abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
   zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
   Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
   Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
   Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
   danach frage.

Aufgabe 3.1: Benachrichtigungen im Fahrrad-Onlineshop (Profilkompetenz)

(ca. 29 min Bearbeitungszeit)

Die CSB-Rad GmbH in Bielefeld informiert ihre Kundschaft über den Stand von Bestellung und Rahmenfertigung: per Mail, per SMS oder als Push-Nachricht in der Shop-App. Du bist Auszubildende*r im Entwicklungsteam. Bisher erledigt das im Shop-Backend (Java) die folgende Klasse:

public class Benachrichtigung {
    private String kanal;      // "MAIL", "SMS" oder "APP"
    private String adresse;    // Mailadresse, Mobilnummer oder Geräte-ID

    public Benachrichtigung(String kanal, String adresse) {
        this.kanal = kanal;
        this.adresse = adresse;
    }

    public String aufbereiten(String text) {
        switch (kanal) {
            case "MAIL": return "Hallo! " + text + " Dein CSB-Rad-Team";
            case "SMS":  return text.length() <= 160 ? text : text.substring(0, 157) + "...";
            case "APP":  return text.length() <= 40 ? text : text.substring(0, 37) + "...";
            default:     throw new IllegalStateException("Unbekannter Kanal: " + kanal);
        }
    }

    public boolean adresseGueltig() {
        switch (kanal) {
            case "MAIL": return adresse.contains("@");
            case "SMS":  return adresse.startsWith("+");
            default:     throw new IllegalStateException("Unbekannter Kanal: " + kanal);
        }
    }
}

a) Seit der Einführung der App-Benachrichtigungen meldet der Shop gelegentlich einen Fehler. Sage voraus, was beim Aufruf new Benachrichtigung("APP", "A7F3-22C9").adresseGueltig() geschieht, und erkläre, warum der Compiler diesen Fehler nicht gefunden hat und warum die Struktur der Klasse solche Fehler begünstigt. (3 Punkte)

  • Der Fall "APP" fehlt in adresseGueltig(). Der Aufruf landet im default-Zweig und bricht mit einer IllegalStateException („Unbekannter Kanal: APP“) ab (1 Punkt).

  • Für den Compiler ist kanal nur irgendein String. Ob jeder mögliche Wert in jeder Methode behandelt wird, kann er nicht prüfen; der Fehler zeigt sich erst zur Laufzeit (1 Punkt).

  • Dieselbe Fallunterscheidung steht in mehreren Methoden. Wer einen neuen Kanal einführt, muss alle diese Stellen finden und ergänzen – eine vergessene Stelle fällt erst im Betrieb auf (1 Punkt).

b) Cem Sarıkaya möchte die Fallunterscheidungen durch Polymorphie ersetzen. Ein Kollege hat dazu den folgenden Entwurf gezeichnet. Er enthält vier Mängel, durch die der polymorphe Ansatz nicht funktioniert oder seine Vorteile verliert. Beschreibe die Mängel und erstelle ein korrigiertes Klassendiagramm. (8 Punkte)

Entwurf eines Klassendiagramms mit der Klasse Kanal, den Unterklassen MailKanal, SmsKanal und AppKanal sowie dem Kundenkonto mit drei Assoziationen zu den Unterklassen (mit KI erstellt)

Je Mangel 1 Punkt für das Erkennen, 1 Punkt für die korrekte Darstellung im Diagramm:

  • Kanal ist eine gewöhnliche Klasse mit konkreten Methoden aufbereiten und adresseGueltig. Eine allgemeine Aufbereitung „für irgendeinen Kanal“ gibt es aber nicht: Kanal wird abstrakt, die beiden Methoden ebenfalls (kursiv bzw. {abstract}). Dann lassen sich keine Kanal-Objekte ohne Kanalart mehr erzeugen, und jede Unterklasse muss beide Methoden implementieren.

  • MailKanal hat aufbereiten(text: String, anrede: String) mit einem zusätzlichen Parameter. Das ist keine Überschreibung, sondern eine Überladung: Ein Aufruf k.aufbereiten(text) über eine Kanal-Referenz würde die Methode aus Kanal ausführen. Die Signatur muss gleich sein: aufbereiten(text: String): String.

  • SmsKanal überschreibt keine der beiden Methoden. Ist Kanal abstrakt, übersetzt der Compiler die Klasse so nicht; SmsKanal braucht eigene Implementierungen von aufbereiten und adresseGueltig.

  • Kundenkonto kennt die drei Unterklassen einzeln. Dann braucht benachrichtigen wieder drei getrennte Schleifen, und für jeden neuen Kanal muss Kundenkonto geändert werden. Richtig ist eine gerichtete Assoziation zur Oberklasse Kanal, Multiplizität 1..* (der Konstruktor verlangt einen ersten Kanal; 0..* wird ebenfalls akzeptiert).

Korrigiertes Klassendiagramm: abstrakte Klasse Kanal mit abstrakten Methoden, drei Unterklassen mit überschriebenen Methoden und eine Assoziation von Kundenkonto zu Kanal (mit KI erstellt)

c) Nach dem Umbau sind die Klassen so umgesetzt (Ausschnitt):

public abstract class Kanal {
    private String adresse;
    public Kanal(String adresse) { this.adresse = adresse; }
    public String getAdresse() { return adresse; }
    public abstract String aufbereiten(String text);
    public abstract boolean adresseGueltig();
    protected String kuerzen(String text, int max) {
        if (text.length() <= max) {
            return text;
        }
        return text.substring(0, max - 3) + "...";
    }
}

public class SmsKanal extends Kanal {
    public SmsKanal(String mobilnummer) { super(mobilnummer); }
    @Override public String aufbereiten(String text) { return kuerzen(text, 160); }
    @Override public boolean adresseGueltig() { return getAdresse().startsWith("+"); }
}
// MailKanal und AppKanal entsprechend der bisherigen Regeln;
// AppKanal.adresseGueltig() liefert true, wenn die Geräte-ID nicht leer ist.

public class Kundenkonto {
    private String name;
    private List<Kanal> kanaele = new ArrayList<>();

    public Kundenkonto(String name, Kanal ersterKanal) {
        this.name = name;
        kanaele.add(ersterKanal);
    }
    public void kanalHinzufuegen(Kanal k) { kanaele.add(k); }

    public int benachrichtigen(String text) {
        int gesendet = 0;
        for (Kanal k : kanaele) {
            if (k.adresseGueltig()) {
                System.out.println(k.getClass().getSimpleName() + ": " + k.aufbereiten(text));
                gesendet++;
            }
        }
        return gesendet;
    }
}

Die Kundin Mira Engel hat drei Kanäle hinterlegt:

Kundenkonto mira = new Kundenkonto("Mira Engel", new AppKanal("A7F3-22C9"));
mira.kanalHinzufuegen(new SmsKanal("0521 9988770"));
mira.kanalHinzufuegen(new MailKanal("mira.engel@example.org"));
int anzahl = mira.benachrichtigen("Dein Rahmen ist lackiert und geht morgen in die Montage.");
System.out.println(anzahl + " Nachricht(en) versendet");

getClass().getSimpleName() liefert den Namen der Klasse, aus der das Objekt erzeugt wurde.

ca) Gib die Ausgabe des Programmausschnitts an. (4 Punkte)

AppKanal: Dein Rahmen ist lackiert und geht mor...
MailKanal: Hallo! Dein Rahmen ist lackiert und geht morgen in die Montage. Dein CSB-Rad-Team
2 Nachricht(en) versendet

Bewertung (4 Punkte): 1 Punkt App-Zeile (der Text hat 56 Zeichen und wird auf 37 Zeichen plus „…“ gekürzt), 1 Punkt Mail-Zeile, 1 Punkt: keine SMS-Zeile, weil 0521 9988770 nicht mit + beginnt und adresseGueltig() deshalb false liefert, 1 Punkt Anzahl 2.

cb) In der Schleife steht nur ein einziger Aufruf k.aufbereiten(text), trotzdem entstehen unterschiedliche Texte. Begründe das und erkläre, warum erst beim Ausführen feststeht, welche Implementierung läuft. (3 Punkte)

  • k hat den Referenztyp Kanal. Der Compiler prüft nur, dass Kanal die Methode aufbereiten(String) deklariert – mehr weiß er über k nicht (1 Punkt).

  • In der Liste stehen Objekte verschiedener Unterklassen, die aufbereiten jeweils mit gleicher Signatur überschreiben. Welche Kanäle eine Kundin hinterlegt hat und in welcher Reihenfolge, steht erst fest, wenn das Programm läuft – im Shop kommen sie aus dem Kundenkonto in der Datenbank (1 Punkt).

  • Bei jedem Schleifendurchlauf wählt die Laufzeitumgebung anhand der Klasse des Objekts, auf das k gerade verweist, die passende Implementierung aus (späte bzw. dynamische Bindung). Dieses Zusammenspiel aus gemeinsamer Oberklasse, Überschreiben und später Bindung heißt Polymorphie (1 Punkt).

d) Für dringende Nachrichten (z. B. „Abholung heute bis 18 Uhr“) soll es eine Eil-SMS geben, die vor den Text „EILT: “ setzt und sonst wie eine SMS funktioniert. Im Team kursieren drei Vorschläge für die Klasse EilSms extends SmsKanal:

// Variante A
@Override public String aufbereiten(String text) { return super.aufbereiten("EILT: " + text); }

// Variante B
@Override public String aufbereiten(String text) { return "EILT: " + super.aufbereiten(text); }

// Variante C
@Override public String aufbereiten(String text) { return aufbereiten("EILT: " + text); }

da) Beurteile die drei Varianten. Gehe dabei auf einen Text mit 158 Zeichen ein. (4 Punkte)

  • Variante A ist richtig: Sie setzt „EILT: “ vor den Text und überlässt das Kürzen auf 160 Zeichen der geerbten Implementierung von SmsKanal. Bei 158 Zeichen entsteht ein 164 Zeichen langer Text, der auf 157 Zeichen plus „…“ gekürzt wird – das Ergebnis hat genau 160 Zeichen (2 Punkte).

  • Variante B kürzt zuerst und setzt das Präfix danach davor. Kurze Texte sehen richtig aus, bei 158 Zeichen entstehen aber 164 Zeichen – die SMS-Grenze wird überschritten (1 Punkt).

  • Variante C ruft ohne super sich selbst auf: Der Aufruf geht über this an die überschriebene Methode von EilSms, die wieder sich selbst aufruft. Die Rekursion endet nie, das Programm bricht mit einem StackOverflowError ab (1 Punkt).

db) Implementiere die Klasse EilSms in Java vollständig mit Konstruktor und der Methode aus Variante A. Ein EilSms-Objekt soll in Kundenkonto ohne Änderung der Klasse verwendet werden können. (3 Punkte)

public class EilSms extends SmsKanal {

    public EilSms(String mobilnummer) {
        super(mobilnummer);                       // Konstruktor von SmsKanal
    }

    @Override
    public String aufbereiten(String text) {
        return super.aufbereiten("EILT: " + text); // Kürzen erledigt SmsKanal
    }
}

Bewertung (3 Punkte): 1 Punkt extends SmsKanal, 1 Punkt Konstruktor mit Aufruf super(mobilnummer), 1 Punkt überschreibende Methode mit gleicher Signatur und Aufruf der Oberklassenmethode. adresseGueltig() wird von SmsKanal geerbt und muss nicht erneut implementiert werden. Weil EilSms (über SmsKanal) ein Kanal ist, nimmt kanalHinzufuegen(k: Kanal) das Objekt ohne Änderung an.

e) Prüfe für jede Zeile, ob sie übersetzt wird. Begründe Deine Entscheidung kurz. Die Zeilen werden nacheinander ausgeführt. (4 Punkte)

Zuweisungen mit unterschiedlichen Referenztypen
Zeile übersetzt? Begründung
Kanal k1 = new EilSms("+49 171 2345678");
SmsKanal s1 = k1;
SmsKanal s2 = (SmsKanal) k1;
Kanal k2 = new Kanal("+49 171 2345678");
Beispiellösung zu den Zuweisungen
Zeile übersetzt? Begründung
Kanal k1 = new EilSms("+49 171 2345678"); ja Eine EilSms ist (über SmsKanal) ein Kanal; eine Oberklassenreferenz darf auf Objekte jeder Unterklasse verweisen.
SmsKanal s1 = k1; nein Der Referenztyp von k1 ist Kanal. Dass dahinter eine EilSms steckt, weiß der Compiler nicht; ein Kanal könnte auch ein MailKanal sein.
SmsKanal s2 = (SmsKanal) k1; ja Mit der expliziten Typumwandlung übernimmt die Entwickler*in die Verantwortung; zur Laufzeit wird geprüft, ob das Objekt wirklich ein SmsKanal ist – hier gelingt es.
Kanal k2 = new Kanal("+49 171 2345678"); nein Kanal ist abstrakt und kann nicht instanziiert werden.

Je Zeile 1 Punkt (Entscheidung und Begründung). Hätte k1 auf einen MailKanal verwiesen, wäre die dritte Zeile ebenfalls übersetzt worden, aber zur Laufzeit mit einer ClassCastException abgebrochen.

f) Ein Kollege findet die vielen Klassen übertrieben. Er schlägt vor, Benachrichtigung zu behalten und nur den Typ des Attributs kanal von String auf eine Aufzählung enum Kanalart { MAIL, SMS, APP } zu ändern. Vergleiche diesen Vorschlag mit der polymorphen Lösung. (3 Punkte)

  • Vorteil des Vorschlags: Tippfehler wie "Sms" sind ausgeschlossen, weil nur die drei Konstanten erlaubt sind; die Änderung ist klein (1 Punkt).

  • Nachteil: Die Fallunterscheidungen bleiben in jeder Methode stehen. Ein neuer Kanal (z. B. ein Messenger) erfordert weiterhin Änderungen an allen switch-Anweisungen der getesteten Klasse; kanalspezifische Daten und Regeln bleiben in einer Klasse vermischt (1 Punkt).

  • Polymorphe Lösung: Ein neuer Kanal ist eine neue Unterklasse, Kundenkonto und vorhandene Kanäle bleiben unverändert (Offen-geschlossen-Prinzip); vergisst die neue Klasse eine Methode, meldet das der Compiler, weil die Methoden in Kanal abstrakt sind. Der Mehraufwand an Klassen lohnt sich, sobald Kanäle häufiger dazukommen oder sich im Verhalten stark unterscheiden (1 Punkt).

Aufgabe 3.2: Raumanzeigen für die E-Ink-Türschilder beim Barcamp (Profilkompetenz)

(ca. 27 min Bearbeitungszeit)

Für das Barcamp „Lernen.Digital.Leben 2027“ am Ratz und Rübe Berufskolleg (RRB) in Bielefeld bekommen alle Sessionräume ein E-Ink-Türschild. Den Text für jedes Türschild berechnet der Info-Server: Für jeden Raum gibt es dort ein Objekt der Klasse Raumanzeige, das einmal pro Minute aktualisiert wird und den neuen Text per MQTT an das Türschild schickt. Du entwickelst die Klasse zusammen mit Mia Schröder (Azubi FIA). Der Text hängt vom Zustand des Raums ab:

  • Im Zustand frei lautet der Text „: frei“. Beginnt laut Sessionplan eine Session, wechselt die Raumanzeige in den Zustand Session läuft.

  • Im Zustand Session läuft zeigt der Text den Sessiontitel und die Restminuten. Jede Minute werden die Restminuten um eins verringert. Sind sie abgelaufen, wechselt die Raumanzeige für 10 Minuten in die Umbaupause.

  • Im Zustand Umbaupause lautet der Text „: Umbaupause“. Nach Ablauf der Pausenminuten ist der Raum wieder frei.

Die Entwicklung erfolgt nach dem Zustand-Entwurfsmuster (State Pattern). Der folgende Entwurf ist noch unvollständig:

Unvollständiges Klassendiagramm mit der Klasse Raumanzeige und den noch leeren Klassen Anzeigezustand, Frei, SessionLaeuft und Umbaupause ohne Beziehungen (mit KI erstellt)

Wie abstrakte Klassen, abstrakte Methoden, Vererbung und gerichtete Assoziationen notiert werden, beschreibt der Artikel Abstrakte Klassen und Interfaces.

a) Ergänze das Klassendiagramm: Kennzeichne die Klasse Anzeigezustand als nicht instanziierbar, ergänze die Methoden anzeigetext(r: Raumanzeige): String und minuteVergangen(r: Raumanzeige) in allen Zustandsklassen passend (abstrakt bzw. überschreibend) und zeichne die Beziehungen zwischen den Klassen mit Multiplizitäten ein. (8 Punkte)

Ergänztes Klassendiagramm der Raumanzeige nach dem Zustand-Entwurfsmuster mit abstrakter Klasse Anzeigezustand und drei Zustandsklassen (mit KI erstellt)

Bewertung (8 Punkte):

  • 1 Punkt: Anzeigezustand als abstrakt gekennzeichnet.

  • 1 Punkt: beide Methoden in Anzeigezustand als abstrakt.

  • 3 Punkte: je Zustandsklasse beide Methoden als überschreibende (konkrete) Methoden mit vollständiger Signatur.

  • 2 Punkte: drei Vererbungsbeziehungen zu Anzeigezustand (1 Punkt bei einem Fehler).

  • 1 Punkt: gerichtete Assoziation von Raumanzeige zu Anzeigezustand mit Multiplizität 1 beim Anzeigezustand, passend zum Attribut zustand. In der Lösung steht zustand als Rollenname am Assoziationsende, das Attribut entfällt deshalb in der Klasse. Bleibt das vorgegebene Attribut stehen und kommt die Assoziation hinzu, gibt es ebenfalls den Punkt.

Abhängigkeiten der Zustandsklassen zu Raumanzeige (über den Parameter r) dürfen zusätzlich als gestrichelte Pfeile eingezeichnet werden, sind aber nicht gefordert.

b) Die Methode aktualisieren() der Klasse Raumanzeige ist so umgesetzt:

public String aktualisieren() {
    zustand.minuteVergangen(this);
    return zustand.anzeigetext(this);
}

Mia meint: „In aktualisieren() fehlt doch die Abfrage, in welchem Zustand der Raum gerade ist.“ Die Raumanzeige für Raum A 204 steht in der Umbaupause, es ist nur noch eine Pausenminute übrig (restminuten = 1). Verfolge, welche Methoden welcher Klassen beim nächsten Aufruf von aktualisieren() nacheinander ausgeführt werden und welcher Text zurückkommt. Widerlege anschließend Mias Einwand. (5 Punkte)

Ablauf (3 Punkte):

  1. zustand verweist auf ein Umbaupause-Objekt. zustand.minuteVergangen(this) führt deshalb Umbaupause.minuteVergangen(r) aus: Die Pausenminuten sinken auf 0, die Methode setzt über r.setZustand(new Frei()) einen neuen Zustand (1 Punkt).

  2. Die zweite Zeile zustand.anzeigetext(this) liest das Attribut erneut. Es verweist jetzt auf das neue Frei-Objekt, also läuft Frei.anzeigetext(r) (1 Punkt).

  3. Rückgabe: „A 204: frei“ (1 Punkt).

Einwand widerlegt (2 Punkte):

  • Das Attribut zustand hat den Typ der abstrakten Klasse Anzeigezustand. Alle Zustandsklassen erben davon und überschreiben beide Methoden mit gleicher Signatur. Raumanzeige muss deshalb nur wissen, dass es einen Anzeigezustand gibt, nicht welchen (1 Punkt).

  • Welche Implementierung ausgeführt wird, entscheidet die Laufzeitumgebung bei jedem Aufruf anhand des Objekts, auf das zustand gerade verweist (späte Bindung) – im Beispiel sogar innerhalb desselben aktualisieren()-Aufrufs zweimal verschieden. Die „Abfrage“ steckt also in der Auswahl der Klasse; eine Fallunterscheidung in Raumanzeige wäre doppelt und müsste bei jedem neuen Zustand geändert werden (1 Punkt).

c) Mia hat die Methode minuteVergangen(r: Raumanzeige) der Klasse SessionLaeuft implementiert. Raumanzeige stellt dazu getRestminuten(): Integer, setRestminuten(minuten: Integer) und setZustand(z: Anzeigezustand) bereit. In Mias Code stecken drei Fehler. Gib jeweils die Zeile an, erkläre, was dort falsch läuft, und notiere die korrigierte Methode. (5 Punkte)

Den Code kannst Du in vier Notationen anzeigen; die Zeilennummern gelten in allen Notationen (Zeile 1 ist der Methodenkopf). Die Notationen sind im Artikel Algorithmen mit Pseudocode dokumentieren beschrieben.

öffentlich Prozedur minuteVergangen(r: Raumanzeige)
    rest: integer := r.getRestminuten() - 1
    wenn rest > 0 dann
        r.setRestminuten(10)
        this.setZustand(new Umbaupause())
    Ende wenn
Ende minuteVergangen

Fehler (je 1 Punkt für Zeile und Erklärung, 3 Punkte):

  1. Zeile 2: Die um eins verringerte Zahl steht nur in der lokalen Variablen rest; die Raumanzeige erfährt davon nichts. Ihre Restminuten sinken nie, das Türschild zeigt immer dieselbe Restzeit, und die Session würde nie enden. Korrektur: den neuen Wert mit r.setRestminuten(rest) an die Raumanzeige zurückgeben.

  2. Zeile 3: Die Bedingung ist umgekehrt. So wechselt die Anzeige in die Umbaupause, solange noch Minuten übrig sind, statt erst dann, wenn sie abgelaufen sind. Korrektur: rest <= 0 (oder Vergleich auf gleich 0).

  3. Zeile 5: this (in Pseudo-Python self) verweist auf das Zustandsobjekt vom Typ SessionLaeuft, nicht auf die Raumanzeige. Welcher Zustand gerade gilt, speichert die Raumanzeige in ihrem Attribut zustand, und nur sie bietet setZustand() an. Der Zustand erreicht die Raumanzeige über den Parameter r. Korrektur: setZustand() auf r aufrufen statt auf this.

Korrigierte Methode (2 Punkte: 1 Punkt für das Verringern und Zurückschreiben der Restminuten mit richtiger Bedingung, 1 Punkt für Pausendauer 10 Minuten und Zustandswechsel über r.setZustand(...) mit einem neuen Umbaupause-Objekt):

öffentlich Prozedur minuteVergangen(r: Raumanzeige)
    rest: integer := r.getRestminuten() - 1
    r.setRestminuten(rest)
    wenn rest <= 0 dann
        r.setRestminuten(10)
        r.setZustand(new Umbaupause())
    Ende wenn
Ende minuteVergangen

Die Signatur bleibt unverändert, denn sie muss zur abstrakten Methode in Anzeigezustand passen, damit SessionLaeuft sie überschreibt.

d) Mia schlägt eine zweite Fassung der Methode anzeigetext vor, die zusätzlich die Sprache übergibt: anzeigetext(r: Raumanzeige, sprache: String): String. Nenne den Fachbegriff für diese Art, eine Methode zu definieren, und erkläre den Unterschied zum Überschreiben. Gehe darauf ein, wann jeweils entschieden wird, welche Methode aufgerufen wird. (4 Punkte)

  • Es handelt sich um Überladen (overloading): gleicher Methodenname, aber andere Parameterliste (zusätzlicher Parameter sprache) (1 Punkt).

  • Beim Überladen entscheidet der Compiler anhand von Anzahl und Typen der Argumente, welche Methode aufgerufen wird (statische bzw. frühe Bindung) (1 Punkt).

  • Überschreiben (overriding) liegt vor, wenn eine Unterklasse eine Methode der Oberklasse mit gleicher Signatur neu implementiert, wie anzeigetext(r: Raumanzeige) in Frei, SessionLaeuft und Umbaupause (1 Punkt).

  • Beim Überschreiben wird erst zur Laufzeit anhand der tatsächlichen Klasse des Objekts entschieden (späte bzw. dynamische Bindung). Nur das Überschreiben ist die Grundlage der Polymorphie im Zustand-Entwurfsmuster (1 Punkt).

e) Die Klasse Raumverwaltung verwaltet alle Raumanzeigen in der Liste -anzeigen: List<Raumanzeige>. Entwirf in Pseudocode die Methode +alleAktualisieren(): List<String>, die jede Raumanzeige aktualisiert und eine Liste aller neuen Anzeigetexte zurückgibt. (4 Punkte)

öffentlich Funktion alleAktualisieren(): Liste von string
    texte: Liste von string := new Liste von string()
    für jedes anzeige in this.anzeigen
        texte.hinzufuegen(anzeige.aktualisieren())
    Ende für
    Rückgabe texte
Ende alleAktualisieren

Bewertung (4 Punkte): 1 Punkt neue Ergebnisliste, 1 Punkt Schleife über alle Raumanzeigen, 1 Punkt Aufruf von aktualisieren() je Raumanzeige und Hinzufügen des Rückgabewerts, 1 Punkt Rückgabe der Liste.

Die Methode muss nicht wissen, in welchem Zustand sich ein Raum befindet: Das passende Verhalten wählt jede Raumanzeige über ihre polymorphe Referenz zustand selbst aus.

f) Am Vortag des Barcamps sollen die Türschilder zusätzlich den Zustand Aufbau zeigen („: Aufbau – bitte nicht betreten“). Nenne die notwendigen Änderungen und erläutere, warum Raumanzeige und Raumverwaltung dafür nicht geändert werden müssen. (3 Punkte)

  • Neue Klasse Aufbau, die von Anzeigezustand erbt und anzeigetext und minuteVergangen überschreibt (1 Punkt).

  • Die Zustandswechsel festlegen: Beim Einrichten am Vortag setzt das Startprogramm des Info-Servers für jede Raumanzeige einmalig anzeige.setZustand(new Aufbau()); Aufbau.minuteVergangen wechselt zum Veranstaltungsbeginn mit r.setZustand(new Frei()) in den Zustand frei (1 Punkt).

  • Raumanzeige und Raumverwaltung arbeiten nur mit dem abstrakten Typ Anzeigezustand und rufen dessen Methoden auf. Durch die späte Bindung wird automatisch die Implementierung der neuen Klasse ausgeführt (1 Punkt).


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zu Polymorphie und später Bindung” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/uml-klassendiagramm-polymorphie-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/uml/uml-diagramme. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 29.10.2026.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: