Fortgeschrittene objektorientierte Programmierung
LVA 185.211, VL 2.0, 2006 S
1. Übungsaufgabe
Entwickeln Sie in Java (am besten Cacao), C# oder C++ ein Programm zur
Lösung folgender Problemstellung:
Benötigt wird eine einfache graphische Oberfläche für ein
einfaches schwarz/weiß-ASCII-Terminal. Insbesondere sollen am Terminal
Fenster darstellbar sein, deren Ränder durch die Zeichen |
(vertikal), -
(horizontal) und +
(an den Ecken) gezeichnet sind.
Es sollen gleichzeitig mehrere Fenster (auch überlappend) darstellbar
sein. Aktiv ist immer das vorderste Fenster unter der aktuellen
Cursor-Position (bzw. kein Fenster, wenn der Cursor nicht über einem
Fenster steht).
Tastatureingaben können folgende Objekte betreffen:
- Das ganze Terminal (global):
- Die Bedeutung der Eingabe ist unabhängig davon, welches Fenster
aktiv ist.
- Ein Fenster (lokal):
- Die Eingabe bezieht sich auf das aktive Fenster selbst wenn der Cursor
gerade über dessen Rand steht.
- Die Applikation hinter einem Fenster (lokal):
- Die Eingabe bezieht sich auf die Applikation hinter dem aktiven Fenster
wenn der Cursor über dem Fenster, aber nicht direkt über dessen
Rand steht.
Wenn es ein aktives Fenster gibt, wird für jede Eingabe sowohl eine
globale (das ganze Terminal betreffende) als auch eine lokale (ein Fenster
oder die Applikation dahinter betreffende) Aktion ausgeführt, sonst nur
eine globale. Globale Aktionen werden immer erst nach etwaigen lokalen Aktionen
durchgeführt. Folgende globale Aktionen sollen unterstützt werden:
l
, r
, u
und d
:
- Diese Eingaben Verschieben den Cursor um eine Position nach links,
rechts, oben, bzw. unten, außer wenn der Cursor dadurch ganz aus
dem Terminal verschwinden würde. In letzterem Fall springt der Cursor
an den genau gegenüberliegenden Rand des Terminals. Dabei kann ein
anderes Fenster aktiv werden.
L
, R
, U
und D
:
- Verschieben den Cursur ebenso nach links, rechts, oben, bzw. unten.
Statt aus dem Terminal zu verschwinden (oder an den anderen Rand zu springen)
bleibt der Curser jedoch an seiner derzeitigen Position stehen. Wenn es
zu einer Änderung der Cursor-Position kommt, kann ein anderes Fenster
aktiv werden.
- alle anderen Eingaben:
- Falls ein Fenster aktiv ist, gibt es keinen globalen Effekt.
Andernfalls wird das ganze Terminal für kurze Zeit, ca. eine halbe
bis eine Sekunde, komplett mit
*
-Zeichen gefuellt (Blinkeffekt).
Eingaben, die ein Fenster betreffen, sollen folgende lokale Effekte haben:
l
, r
, u
und d
:
- Bewirken keine lokalen Effekte.
L
, R
, U
und D
:
- Bewirken, dass sich das gesamte aktive Fenster in dieselbe Richtung
verschiebt wie der Cursor.
+
und -
:
- Bewirkt eine Vergrößerung bzw. Verkleinerung des aktiven
Fensters. Dabei wird der Rand des Fensters, über dem der Cursor steht,
verschoben. Steht der Cursor über einer Ecke des Fensters, werden
beide angrenzenden Ränder verschoben. Auch die aktuelle
Cursor-Position muss (ohne Unterstützung durch eine globale Aktion)
entsprechend verschoben werden. Die Eingabe hat keinen Effekt, wenn das
Fenster dabei auf Größe 0 reduziert oder der Cursor aus dem
Terminal verschwinden würde.
b
:
- Bewirkt, dass das aktive Fenster ganz nach hinten geschoben wird, damit
andere Fenster, die sich möglicherweise hinter dem derzeit aktiven
befinden, aktiviert werden.
- alle anderen Eingaben:
- Das ganze Fenster (inklusive Rand) wird für kurze Zeit komplett mit
*
-Zeichen gefuellt.
Jedem Fenster ist genau eine Applikation zugeordnet, und jede Applikation
hat genau ein Fenster. Als Beispielapplikation soll ein kleines Zeichenprogramm
(kann auch ein Programmteil sein) dienen: An jeder Position (= Cursor-Position)
der Zeichnung steht entweder ein Leerzeichen oder *
.
Folgende Tastatureingaben sollen von der Applikation verarbeitet werden:
s
:
- Speichert die Zeichnung im aktiven Fenster permanent.
q
:
- Speichert die Zeichnung im aktiven Fenster und beendet die Applikation,
wobei das Fenster entfernt wird. Falls es keine weiteren Fenster mehr
am Terminal gibt, endet das gesamte Programm.
x
:
- Beendet die Applikation und entfernt das aktive Fenster, ohne die
Zeichnung permanent zu speichern. Falls es keine weiteren Fenster mehr
am Terminal gibt, endet das gesamte Programm.
L
, R
, U
und D
:
- Bewirken, dass sich das Zeichen unter dem Cursor verändert -
ein Leerzeichen zu einem Stern und umgekehrt.
l
, r
, u
und d
:
- Haben keine lokalen Effekte.
0
bis 9
:
- Bewirken, dass eine unter der entsprechenden Nummer permanent
gespeicherte Zeichnung geladen und in einem neuen Fenster dargestellt wird.
Größe und Position des Fensters sind so wie vor der letzten
Speicherung, und es befindet sich ganz vorne. Ein und dieselbe Zeichnung
darf sich nur in einem Fenster befinden. Statt eine Zeichnung, die schon in
Verwendung ist, nocheinmal zu öffnen, wird das aktive Fenster (mit
Rand) für kurze Zeit komplett mit
*
-Zeichen gefuellt.
b
:
- Bewirkt, dass das aktive Fenster ganz nach hinten geschoben wird.
- alle anderen Eingaben:
- Das ganze Fenster (inklusive Rand) wird für kurze Zeit komplett mit
*
-Zeichen gefuellt.
Bei Programmstart soll automatisch die Zeichnung mit der Nummer 0 geladen
werden.
Es soll möglich sein, dass von mehreren Terminals aus gleichzeitig auf die
persistenten Zeichnungen zugegriffen wird (mehrere Programmstarts). Jedoch
soll es nicht möglich sein, dass Zeichnungen mit derselben Nummer auf
verschiedenen Terminals gleichzeitig offen sind. Daher soll eine Zeichnung nur
dann geladen werden, wenn auf keinem anderen Terminal, das auf denselben
persistenten Speicher zugreift, eine Zeichnung mit dieser Nummer existiert.
Auch in diesem Fall soll beim Versuch, die Zeichnung zu laden, nur das Fenster
kurz blinken, oder das Programm gleich beendet werden, falls beim Start die
Zeichnung 0 nicht verfügbar ist.
Gestalten Sie Ihre Lösung möglichst einfach und gut wartbar. Denken
Sie daran, dass Fenster und Beispielapplikation möglichst unabhängig
voneinander austauschbar sein sollen. Persistente Daten sollen auch in neueren
Versionen des Zeichenprogramms verwendbar sein. Überlegen Sie sich
geeignete Möglichkeiten zur Synchronisation mehrerer Terminals mit
gemeinsamem persistenten Speicher und bedenken Sie, dass der gewählte
Synchronisationsmechanismus später vielleicht gegen einen anderen
ausgetauscht werden muss. Verwenden Sie ganz bewusst Softwareentwurfsmuster,
die Ihnen für diese Anwendung geeignet erscheinen, und vermeiden Sie
ebenso bewusst Entwurfsmuster, deren Einsatz Ihnen hier nicht für
gerechtfertigt erscheint.
Die eigentliche Bildschirmausgabe können Sie einfach gestalten.
Beispielsweise können Sie nach jeder Eingabe oder einmal pro Sekunde
(oder in kürzeren Intervallen) den aktuellen Bildschirminhalt neu
ausgeben.