Es ist mal wieder Weihnachten und meine aktuellen 11. Klässler dürfen mal wieder die Wunschzettel-Verwaltung für den Nikolaus/Weihnachtsmann/Christkind programmieren. Dahinter steckt die Aufgabe 44, die ich vor zwei Jahren schon veröffentlich habe.

Inzwischen haben sich aber nicht nur die Schüler verändert, sondern auch Java und ich muss mich in neue Themen einarbeiten, die ich bislang nicht kannte. In diesem Fall die Generics. Aber eins nach dem anderen.

1. Die ursprüngliche Lösung

Die eigentlich von mir gedachte Lösung sieht ungefähr so aus:

Bildschirmfoto 2014-11-30 um 10.32.41Links oben erkennt man das typische Kompositum-Entwurfsmuster für die Listenstruktur. Damit ich verschiedenartigen Listen verwalten kann, gibt es einen abstrakte Inhaltsklasse, so das aus Sicht der Knoten die Inhalte nach „außen“ alle gleich aussehen – so erkläre ich das immer meinen Schüler. Abstrakte Klassen kann man wie leere Überraschungseier verstehen. Man kann sie aufmachen und irgendwas reintun, aber nach außen wirken alle gleich und können daher auch gleich behandelt werden.

Rechts unten sieht man, dass die eigentlich zu speichernden Inhalte Spezialfälle dieser abstrakten Basisklasse sind. Jedes FamilienMitglied hat eine Liste mit Wünschen, jede Familie kann besteht aus einer Liste/Reihe von FamilienMitgliedern. Die Mitglieder als auch die Wünsche lassen sich über eine GUI anlegen. Die Klasse JNUmberField ist eine Spezialklasse, die vom Java-Editor benutzt wird.

Das eigentlich Problem oder Herausforderung ist die Verwaltung der Wunschliste. Denn hier kann man Prioritäten eingeben: Welches Geschenk ist absolut notwendig, welches nur nett, etc. Dabei hat ein Geschenk mit Priorität 0 die oberste Priorität.

Um das zu ermöglichen bekommt jedes Listenelement ein zusätzlich Attribut priority. Das Attribut bestimmt, wo in der Liste das Element aufgenommen wird. Damit habe ich in der Programmierung der Knoten folgende zwei Implementierungen:

public Listenelement append(Inhalt neuesInhalt) {
        next = next.append(neuesInhalt);
        return this;
}
  
public Listenelement append(Inhalt neuerInhalt, int priority) {
       //Priorätät beginnend mit der kleinsten
       //Da mit einer leeren Liste begonnen wird, 
       //stimmt die Sortierung immer
       //Es wird daher eingefügt, wenn die Priorität < oder = ist

       if (priority <= this.priority) {
            Knoten neuerKnoten = new Knoten(neuerInhalt,priority);
            neuerKnoten.setNext(next);
            next = neuerKnoten;
       } else {
           //Neue priorität ist größer -> weitergegeben.
            next = next.append(neuerInhalt, priority);
       }
       return this;
}

Diese Implementierung funktioniert soweit, nur gibt es natürlich zwei Probleme:

  1. Prinzipiell ließen sich in einer Liste nur Familien, FamilienMitglieder und Wünsche mischen, was ja keinen Sinn machen würde. Man müsste als in der Listenklasse kontrollieren, ob der Inhaltstyp des neuen Inhalts zum Typ der Liste passt.
  2. Beide append-Methoden sind nur Spezialfälle oder Umsetzungsstrategien einer allgemeinen Methode für das Einfügen von Elementen.

Das aus meiner Sicht leichter zu lösende Problem wäre in diesem Fall das Zweite. Hier könnte man mit dem Strategie-Entwurfsmuster arbeiten.

Das Schwierigere oder Neue ist für mich die Lösung des ersten Problems. Hier habe ich immer öfters Schüler, die auf Generics zurückgreifen. Gerechtfertigt, wie ich denke. Wie nun beides konkret umgesetzt wird, zeige ich in den folgenden Teilen.

Zum Schluss noch den aktuellen Source-Code zum runterladen: Nikolausliste