Objektorientierte Programmierung
LVA 185.162, VL 2.0, 2009 W
7. Laborübungsaufgabe
Themen:
kovariante Probleme, mehrfaches dynamisches Binden
Termine:
| Ausgabe: |
02.12.2009 |
| reguläre Abgabe: |
09.12.2009, 13:45 Uhr |
| nachträgliche Abgabe: |
16.12.2009, 13:45 Uhr |
Abgabeverzeichnis:
Gruppe/Aufgabe7
Programmaufruf:
java Test
Grundlage:
Skriptum bis Seite 134, Schwerpunkt auf Abschnitt 3.4
Aufgabe
Welche Aufgabe zu lösen ist:
Entwickeln Sie einen Teil einer Anwendung zur Konfiguration von Computern, wobei Mainboards, Prozessoren und Hauptspeicher als wesentliche Komponenten angesehen werden:
- Es werden zwei Arten von Speichermodulen verwendet, DDR2 und DDR3, die sich in ihren Schnittstellen unterscheiden und nicht gegeneinander austauschbar sind.
Beide Speicherarten gibt es in unterschiedlichen Geschwindigkeitsklassen.
Nur die folgenden Geschwindigkeitsklassen werden unterstützt: 333, 400, 533, 667, 800 und 1066 MHz, bei DDR3 zusätzlich 1333 und 1600 MHz.
- Es gibt viele unterschiedlicher Prozessoren, die sich in Prozessorreihen einteilen lassen.
In der Regel passt ein Prozessor nur in einen für eine Prozessorreihe spezifischen Sockel am Mainboard (z.B. Socket1156, Socket775, SocketAM3 und SocketAM2plus).
Nur Prozessoren, die für SocketAM3 entwickelt wurden, passen auch in ein Mainbord mit SocketAM2plus.
Einige Prozessorreihen enthalten bereits die Ansteuerung für den Hauptspeicher (z.B. Socket1156 für DDR3, SocketAM2plus für DDR2 und SocketAM3 für beide Speicherarten), andere überlassen diese Aufgabe dem Mainboard (z.B. Socket775).
Ein SocketAM3-Prozessor unterstützt DDR3 wenn er in einem SocketAM3-Mainboard steckt, aber nur DDR2 in einem SocketAM2plus-Mainboard.
Je nach Prozessor (nicht direkt abhängig vom Sockel) ist die maximale Geschwindigkeit für Speicherzugriffe entsprechend den oben genannten Geschwindigkeitsklassen begrenzt.
- Ein Mainboard enthält neben zahlreichen anderen Teilen einen Sockel für einen Prozessor und mehrere (= zwei bis acht) Sockel für Speichermodule gleicher Art.
Die Geschwindigkeit für Speicherzugriffe kann weder das vom Mainboard, noch das vom Prozessor oder Speicher vorgegebene Maximum überschreiten.
Bei manchen Mainboards hängt die Maximalgeschwindigkeit für Speicherzugriffe von der Anzahl der belegten Speicher-Sockel ab:
Wenn mehr als eine bestimmte Anzahl an Sockeln belegt ist, verringert sich die Maximalgeschwindigkeit des Mainboards.
Es wird eine Methode benötigt, die für eine bestimmte Konfiguration (bestehend aus einem Mainboard, einem Prozessor und ein bis acht gleichen Speichermodulen) die optimale (= höchstmögliche) Geschwindigkeitsklasse für Speicherzugriffe berechnet.
Die Methode soll 0 zurückgeben, wenn die Komponenten nicht zusammenpassen.
Speichermodule, Prozessoren und Mainboards sollen jeweils als Objekte dargestellt werden.
Zumindest unterschiedlichen Arten von Speichermodulen und unterschiedliche Prozessorreihen sollen je einen eigenen Typ haben.
In der Lösung der Aufgabe (abgesehen von der Testklasse) dürfen Sie folgende Sprachkonzepte nicht verwenden:
- dynamische Typabfragen und Typumwandlungen,
- bedingte Anweisungen wie if- und switch-Anweisungen sowie bedingte Ausdrücke (= Ausdrücke der Form x?y:z)
- Werfen und Abfangen von Ausnahmen
Bauen Sie Ihre Lösung stattdessen auf (mehrfaches) dynamisches Binden auf.
Die Klasse Test soll wie üblich die wichtigsten Normal- und Grenzfälle überprüfen und die Ergebnisse in allgemein verständlicher Form darstellen.
Warum die Aufgabe diese Form hat:
Die Aufgabe lässt Ihnen viel Entscheidungsspielraum.
Es gibt zahlreiche sinnvolle Lösungsvarianten.
Die Form der Aufgabe legt die Verwendung kovarianter Eingangsparametertypen nahe, die aber tatsächlich nicht unterstützt werden.
Daher wird mehrfaches dynamisches Binden (durch simulierte Multi-Methoden bzw. das Visitor-Pattern) bei der Lösung hilfreich sein.
Alternative Techniken, die auf Typumwandlungen und dynamischen Typabfragen beruhen, sind ausdrücklich verboten.
Durch das Verbot bedingter Anweisungen und ähnlicher Sprachkonstrukte wird die Notwendigkeit für dynamisches Binden noch verstärkt.
Sie sollen sehen, wie viel mit dynamischem Binden möglich ist, aber auch, wo ein übermäßiger Einsatz zu Problemen führen kann.
Anders als bei den vorangegangenen Aufgaben gibt es keine vorgeschriebenen Testfälle, die zur Selbstkontrolle genutzt werden könnten.
Was im Hinblick auf die Beurteilung zu beachten ist:
Schwerpunkte bei der Beurteilung liegen auf der selbständigen Entwicklung geeigneter Untertypbeziehungen und dem Einsatz (mehrfachen) dynamischen Bindens.
Kräftige Punkteabzüge gibt es für
- die Verwendung der verbotenen Sprachkonzepte,
- Verletzungen des Ersetzbarkeitsprinzips (also Vererbungsbeziehungen, die keine Untertypbeziehungen sind)
- und nicht der Aufgabenstellung entsprechende oder falsche Funktionalität des Programms.
Punkteabzüge gibt es unter anderem auch für mangelhafte Zusicherungen, schlecht gewählte Sichtbarkeit und unzureichendes Testen (= eine grundlegende Funktionalität wird nicht überprüft).
Wie die Aufgabe zu lösen ist:
Vermeiden Sie Typumwandlungen, dynamische Typabfragen und bedingte Anweisungen von Anfang an, da es schwierig ist, diese aus einem bestehenden Programm zu entfernen.
Akzeptieren Sie in einem ersten Entwurf eher kovariante Eingangsparametertypen bzw. Multimethoden und lösen Sie diese dann so auf, dass Java damit umgehen kann.
Ein vollständiger Verzicht auf bedingte Anweisungen kann ungeahnte Schwierigkeiten nach sich ziehen.
Beispielsweise ist es gar nicht leicht, die Maximalgeschwindigkeit für Speicherzugriffe von der Anzahl der belegten Speicher-Sockel abhängig zu machen.
Ein kleiner Trick kann helfen:
Nachdem die Anzahl möglicher Speichermodule eingeschränkt ist, braucht man nur ein Array vorgeben, das die Anzahl der Module auf die Maximalgeschwindigkeit abbildet.
Dieser Trick und ähnliche Techniken sind an Stelle vieler bedingter Anweisungen einsetzbar.
Trotzdem sollen Sie sparsam damit umgehen, da Sie dabei den Wertebereich einschränken und Erweiterungen erschweren.
Dynamisches Binden ist aus Sicht der Wartbarkeit vorteilhaft.
Halten Sie die Anzahl der Klassen, Interfaces und Methoden möglichst klein und überschaubar.
Durch die Aufgabenstellung ist eine große Anzahl an Klassen und Methoden ohnehin kaum vermeidbar, und durch weitere unnötige Strukturierung oder Funktionalität könnten Sie bald den Überblick verlieren.
Einfachheit ist gerade bei der Lösung dieser Aufgabe ein großer Pluspunkt.
Wie in der letzten Aufgabe gibt es mehrere sinnvolle Lösungsansätze.
Bleiben Sie bei dem ersten von Ihnen gewählten sinnvollen Ansatz und probieren Sie nicht zuviel herum, damit Ihnen nicht die Zeit davonläuft.
Was im Hinblick auf die Abgabe zu beachten ist:
Verzichten Sie wie üblich auf die Verwendung von packages und Verzeichnissen innerhalb des Abgabeverzeichnisses.
Gerade für diese Aufgabe ist es besonders wichtig, dass Sie (abgesehen von geschachtelten Klassen) nicht mehr als eine Klasse in jede Datei geben und auf aussagekräftige Namen achten.
Sonst ist es schwierig, sich einen Überblick über Ihre Klassen und Interfaces zu verschaffen.
Achten Sie darauf, dass Sie keine Java-Dateien abgeben, die nicht zu Ihrer Lösung gehören (alte Versionen, Reste aus früheren Versuchen, etc.).