Wie wir bereits wissen, besitzen Objekte einen Zustand und ein Verhalten. Der Zustand wird durch die Properties beschrieben und das Verhalten durch die Funktionen. Der Zustand eines Objekts kann verändert werden. Solche Zustandsübergänge wollen wir am Beispiel einer Ampel erst selbst implementierung und in einem grafischen Modell erfassen. Hierbei lernen wir Zustandsübergangsdiagramme und Sequenzdiagramme kennen.
Ampel
Es soll eine Ampel programmiert werden, welche ihre Zustände (die Ampelphasen) speichert und diese durch Zustandsübergänge ineinander überführt: Nach einer Rot-Phase kommt eine Rot-Gelb-Phase und anschließend die Grün-Phase.
Also Vorlage dient das nebenstehend verlinkte Projekt. Importieren Sie es in Ihre IDE und arbeiten Sie parallel zu dieser Anleitung mit
Planung
Um es bei der Implementierung möglichst einfach zu haben, planen wir das Projekt ausführlich. Dazu erstellen wir ein strukturelles und ein verhaltensorientiertes Modell mit Hilfe von Visualsierungsmethoden (Diagrammen) der UML.
Struktur
Das Klassendiagramm zeigt die Struktur unserer Programms. Implementieren Sie alle Klassen in das Projekt, so dass das Klassendiagramm korrekt im Code manifestiert. Erzeugen Sie also alle Klassen, die noch nicht in der Vorlage mitgeliefert werden und fügen Sie alle Funktionen und Properties entsprechend dem Klassendiagramm ein. Die KlassenKreis
und Rechteck
sind Teil der engineEmi.
Enum-Klassen
Neu sind die beiden Enumeration Klassen. Eine Enumeration ist eine Aufzählung und hilft uns, Zustände semantisch verständlicher zu speichern. Betrachten Sie hierzu folgenden Code:
Natürlich könnten wir die Zustände auch einfach in Form von Ziffern oder anderen Datentypen speichern. Enums helfen uns aber, den Code leserlich zu halten, ohne ihn mit ausufernden Kommentaren und Erklärungen versehen zu müssen. Sie helfen uns auch dabei, unseren Code gegen (Laufzeit)Fehler abzusichern. Betrachten Sie hierzu das folgende Beispiel:
Zustandsmodellierung
Mit Hilfe der Enum-Klassen modellieren wir verschiedene Zustände der Ampel (die Phasen) und der Lampen (die Zustände An und Aus). Diese können in Zustandsdiagrammen visualisiert werden.
Zustandsdiagramme sind übrigens auch Teil der UML.
Bitte achten Sie bei der Implementierung genau darauf, wie wir die einzelnen Zustände und deren Zustandsübergänge implementieren.
Implementierung
1. Main.kt
Öffnen Sie die Main.kt
und konfigurieren Sie die engine im init
Block, so dass der View eine Höhe von 400 und eine Breite von 200 erhält.
engine.view.height = 400
engine.view.width = 200
2. Gehäuse
Überprüfen Sie Ihre Gehäuse Klasse. Sie soll von Rechteck
erben und das dargestellte Gehäuse soll die Hintergrundfarbe Colors.DARKGRAY
besitzen und an den Koordinaten (50,50) platziert werden. Der Konstruktor soll die Breite und die Höhe als Parameter entgegen nehmen. Die Höhe soll auf 300 gesetzt werden, die Breite auf 100.
Hinweis: Die Klasse Gehaeuse
ist sehr kurz und übersichlich. In solchen Fällen muss man hierfür nicht unbedingt eine eigene *.kt Datei erzeugen. Die Klasse darf ohne Weiteres innerhalb der Datei Ampel.kt
platziert werden.
3. Lampe
Die Klasse Lampe
muss noch teilweise vervollständigt werden:
anzeigeAktualisieren()
Diese Funktion dient dazu, den internen Zustand (welcher in der Variable zustand
gespeichert ist) auch visuell zu repräsentieren, nämlich ob die Lampe an oder aus ist. Überprüfen Sie mit Hilfe eines bedingten Ausdrucks, welche Ausprägung die Variable zustand
gerade hat und setzen Sie die alpha
property der Lampe
(die sie von Kreis
geerbt hat) wie folgt:
Falls an -> 1.0
Falls aus -> 0.1
an(), aus(), schalten()
Implementieren Sie diese Methoden so, dass die Variable zustand
(je nach Funktion) korrekt gesetzt wird. Nach dem Setzen, soll jedes Mal die Funktion anzeigeAktualisieren()
aufgerufen werden, so dass die Änderung auch sichtbar wird.
4. Ampel.kt
Vielleicht ist Ihnen aufgefallen, dass die Datei Ampel.kt keine Ampel-Klasse (mit dem Schlüsselwort class) enthält, sondern mit dem Schlüsselwort object beginnt. Hierbei handelt es sich um ein sogenanntes Singleton. Ein Singleton ist eine Klasse, von der nur ein einziges Objekt erzeugt werden kann. In unserem Projekt existiert nur eine einzige Ampel. Daher ist es nicht notwendig, mehrere Objekte (mehrere Instanzen) der Klasse Ampel erzeugen zu können. Dies erleichtert uns auch den Zugriff auf die internen Zustände der Ampel:
Ampel-Phasen
Die Ampel-Phasen speichern wir im Array phasen
. Diese Phasen geben genau die einzelnen Zustände aus dem oben gezeigten Zustandsdiagramm wieder. Sie sind in der enum-Klasse Phase
modelliert.
Die schalten-Funktion
Diese Funktion soll die einzelnen Lampen der Ampel in die korrekte Konfiguration schalten. Also je nach Phase die entsprechenden Ampelfarben an oder aus schalten.
Implementieren Sie die Funktion so, dass die fünf verschiedenen Ampel-Phasen die korrekten Lampen schalten. Die entsprechende Phase wird im Funktions-Parameter übergeben.
reactToKeyEvent
Wir wollen erreichen, dass die Ampelphasen durch das Drücken der Leertaste geschalten werden. Die Transitionen im Zustandsdiagramm finden also durch das Drücken der Leertaste statt.
Bei Tastatureingaben handelt es sich um sogenannte KeyEvent
s. Diese werden als ‘KeyEvent’ Objekt mit dem Bezeichner event
als Parameter dieser Funktion übergeben. Implementieren Sie diese Funktion so, dass Folgendes erreicht wird:
event.key == Key.SPACE //muss true sein
event.type == KeyEvent.Type.DOWN // muss true sein
// Falls beide Bedingungen wahr sind:
// rufe die Funktionen auf:
naechstePhase() // schaltet eine Phase weiter
schalten(phasen[aktuellePhase]) // bringt die korrekten Lampen zum Leuchten
istGruen()
Als kleinen Bonus sollte noch diese Funktion implementiert werden. Sie sollte immer dann true
als Rückgabewert liefern, wenn die Ampel in der Grün-Phase ist.
Das fertige Projekt sollte dann in etwa so aussehen:
Verhaltensmodellierung
Um das Verhalten zu modellieren, existieren Sequenzdiagramme. Ein denkbares Sequenzdiagramm für das Umschalten von der Rot-Phase in die Rotgelb-Phase könnte wie folgt aussehen:
Eine gute Erklärung zur Erstellung von Sequenzdiagrammen finden Sie in diesem Video.