Objektorientierte Programmiertechniken
LVA 185.A01, VU, 3 ECTS, 2016/2017 W
| Ausgabe: | 23.11.2016 |
| Abgabe: | 30.11.2016, 12:00 Uhr |
Before beschreibt die boolesche Methode before, die den Methodenparameter (der ungleich null sein muss) mit this vergleicht.
Folgende Bedingungen gelten:
x.equals(y) (für beliebige x und y) als Ergebnis true liefert, dann muss x.before(y) als Ergebnis false liefern.
x.before(y) und y.before(z) jeweils true liefern, dann muss auch x.before(z) true zurückgeben.
x.before(y) true liefert, dann muss y.before(x) false liefern.
x.before(y) liefern dasselbe Ergebnis, soferne x und y zwischen den Aufrufen nicht verändert wurden.
Sorted stellt eine Ansammlung von entsprechend Before sortierbaren Objekten dar, deren Typen durch einen Typparameter bestimmt werden.
Sorted implementiert das Interface java.lang.Iterable sowie folgende Methoden:
add fügt den Methodenparameter in die Ansammlung ein.
In der Ansammlung können Objekte mehrfach vorkommen.
iterator liefert als Ergebnis einen Iterator über alle Objekte in der Ansammlung, wobei über mehrfach vorkommende Objekte auch entsprechend oft iteriert wird.
Für alle Objekte x und y in der Ansammlung gilt, dass der Iterator x vor y behandeln muss wenn x.before(y) true liefert.
Der Iterator muss auch remove implementieren und darf keine UnsupportedOperationException werfen (siehe java.lang.Iterator).
Clustered ist eine Ansammlung von entsprechend Before sortierbaren Objekten, die (ergänzend zu Sorted) Clustern zugeordnet sein können.
Clustered<A,B> ist für geeignete Typen A und B ein Untertyp von Sorted<B>, wobei A den Typ von Cluster-Selektoren (siehe unten) beschreibt.
Folgende Methoden sind implementiert:
add mit zwei Methodenparametern fügt den ersten Parameter in die Ansammlung ein.
Der zweite Parameter ist ein Array von Cluster-Selektoren.
Jeder Cluster-Selektor in diesem Array beschreibt ein Cluster, dem das eingefügte Objekt zugeordnet wird.
Gleiche Cluster-Selektoren (auch wenn nicht identisch) beschreiben denselben Cluster.
add mit nur einem Methodenparameter entspricht add mit zwei Parametern, wobei der zweite Parameter ein leeres Array ist.
iterator mit einem Cluster-Selektor als Methodenparameter gibt einen Iterator zurück, der nur über alle dem entsprechenden Cluster zugeordneten Objekte in der Ansammlung iteriert.
Hinsichtlich mehrerer Vorkommen und der Reihenfolge der Iterationen gilt das gleiche wie für iterator in Sorted.
iterator ohne Methodenparameter gibt einen Iterator über alle Objekte in der Ansammlung zurück, wie in Sorted (ohne Berücksichtigung von Clustern).
SquirelRanking, die das Interface Before<...> implementiert, enthalten je eine Fließkommazahl, die über den Konstruktor gesetzt wird und unveränderlich ist.
Ein Aufruf von x.before(y) gibt true zurück wenn die Fließkommazahl in x mindestens doppelt so groß wie die in y ist.
SquirelRanking hat KEINE Untertypbeziehung zum Typ SquirelFood.
SquirelFood implementiert Before<...>.
Ein Objekt von SquirelFood beschreibt Brennwert und Fettgehalt eines Nahrungsmittels.
Diese Werte werden über den Konstruktor gesetzt und sind unveränderlich.
Ein Aufruf von x.before(y) gibt true zurück wenn der Brennwert oder Fettgehalt von x den entsprechenden Wert von y um mindestens 20% übersteigt.
Nut erweitert SquirelFood um Informationen zur Härte der Nussschale, angegeben durch einen der Buchstaben A bis G.
Fruit erweitert SquirelFood um die Angabe der Haltbarkeit in Tagen (als ganze Zahl).
Ein Aufruf von java Test soll wie gewohnt Testfälle ausführen und die Ergebnisse in allgemein verständlicher Form darstellen.
Anders als in bisherigen Aufgaben sind die Überprüfungen jedoch vorgegeben und in dieser Reihenfolge auszuführen:
Sorted<Nut>, Clustered<Integer,SquirelRanking>, Clustered<String,Nut> und Clustered<String,Fruit>.
Überprüfen Sie die Funktionalität durch Einfügen einiger Elemente, Ausgeben der von Iteratoren zurückgegebenen Elemente, Entfernen einiger Elemente, Einfügen weiterer Elemente und erneutes Ausgeben, sodass alle wesentlichen Eigenschaften der oben beschriebenen Typen sichtbar werden.
Vergessen Sie nicht, bei Objekten des Typs Nut die Härte der Nussschale und bei Objekten des Typs Fruit die Haltbarkeit auszugeben.
Clustered<String,SquirelFood>.
Lesen Sie über Iteratoren alle Elemente aus den in Punkt 1 erzeugten Datenstrukturen der Typen Clustered<String,Nut> und Clustered<String,Fruit> aus und fügen Sie diese in die neue Datenstruktur ein.
Überprüfen Sie die Funktionalität wie in Punkt 1, allerdings ohne die Härten bzw. Haltbarkeiten von Nüssen und Früchten auszugeben.
Sorted<SquirelFood> wäre (z.B., indem Sie die Datenstruktur an eine Variable vom deklarierten Typ Sorted<SquirelFood> zuweisen und die Tests auf dieser Variablen ausführen).
Testen Sie die Funktionalität wie in Punkt 2, allerdings ohne die zusätzliche Funktionalität von Clustered zu verwenden.
Daneben soll die Klasse Test.java als Kommentar eine kurze, aber verständliche Beschreibung der Aufteilung der Arbeiten auf die einzelnen Gruppenmitglieder enthalten – wer hat was gemacht.
Alle Teile dieser Aufgabe sind ohne Verwendung von Arrays, ohne vorgefertigte Container-Klassen (wie LinkedList, HashSet, etc.) und ohne vorgefertigte Iterator-Implementierungen zu lösen. Benötigte Container und Iteratoren sind selbst zu schreiben.
Typsicherheit soll so weit wie möglich vom Compiler garantiert werden.
Auf die Verwendung von Typumwandlungen (Casts) und ähnliche Techniken ist zu verzichten, und der Compiler darf keine Hinweise auf mögliche Probleme im Zusammenhang mit Generizität geben.
Achtung: Übersetzen Sie die Klassen mittels javac -Xlint:unchecked *.java; dieses Compiler-Flag schaltet genaue Compiler-Meldungen im Zusammenhang mit Generizität ein.
Andernfalls bekommen Sie auch bei schweren Fehlern vom Compiler nur eine harmlos aussehende Meldung (Note: ...
).
Überprüfungen durch den Compiler dürfen nicht ausgeschaltet werden, auch nicht für Warnungen.
Durch die Typhierarchie auf SquirelFood, Nut und Fruit muss Generizität über mehrere Ebenen hinweg betrachtet werden, da vereinfachende Sichtweisen durch von dieser Hierarchie unabhängige Typen ausgeschlossen sind.
Vorgegebene Testfälle stellen sicher, dass die Schwierigkeiten erkannt werden. Um Umgehungen zu vermeiden sind Typumwandlungen ebenso verboten wie das Ausschalten von Compilerhinweisen auf unsichere Verwendungen von Generizität. Neben Techniken zur Lösung der speziellen Schwierigkeiten wird in dieser Aufgabe auch der Umgang mit Sichtbarkeit und Untertypbeziehungen auf generischen Typen geübt. Am Beispiel von Iteratoren soll intuitiv klar werden, welchen Einfluss die Verwendung innerer Klassen auf die Sichtbarkeit von Implementierungsdetails nach außen hat.
| Generizität zusammen mit geforderten Untertypbeziehungen richtig verwendet, sodass die Tests (ohne Tricks beim Testen) durchführbar sind | 40 Punkte |
| Zusicherungen richtig und sinnvoll eingesetzt | 15 Punkte |
| Sichtbarkeit auf so kleine Bereiche wie möglich beschränkt | 15 Punkte |
| Lösung wie vorgeschrieben und sinnvoll getestet | 20 Punkte |
| Geforderte Funktionalität vorhanden (so wie in Aufgabenstellung beschrieben) | 10 Punkte |
Am wichtigsten ist die sinnvolle und korrekte Verwendung von Generizität. Es gibt bedeutende Punkteabzüge, wenn der Compiler mögliche Probleme im Zusammenhang mit Generizität meldet oder wichtige Teilaufgaben nicht gelöst oder umgangen werden.
Ein zusätzlicher Schwerpunkt liegt auf dem gezielten Einsatz von Sichtbarkeit.
Es gibt Punkteabzüge, wenn Programmteile, die überall sichtbar sein sollen, nicht public sind, oder Teile, die nicht für die allgemeine Verwendung bestimmt sind, unnötig weit sichtbar sind.
Durch die Verwendung innerer Klassen kann das Sichtbarmachen mancher Programmteile nach außen verhindert werden.
Nach wie vor spielen auch Untertypbeziehungen und Zusicherungen eine große Rolle bei der Beurteilung.
Generell führen Abänderungen der Aufgabenstellung – beispielsweise die Verwendung von Typumwandlungen, Arrays oder vorgefertigten Containern und Iteratoren oder das Ausschalten von Überprüfungen durch @SuppressWarning – zu bedeutenden Punkteabzügen.