Kapitel 8: Zustände: Unterschied zwischen den Versionen
(→Implementierung von Zustandsdiagrammen in Java) |
|||
Zeile 156: | Zeile 156: | ||
− | <big>[[Aufgaben 8. | + | <big>[[Aufgaben 8.4.]]</big> |
Aktuelle Version vom 4. Mai 2014, 16:23 Uhr
Durch die Veränderung des Wertes eines Attributes wird der Zustand eines Objektes verändert. Diese Zustandsänderung kannn durch unmittelbare Zuweisung eines neuen Wertes an das Attribut oder durch indirekte Wertzuweisung durch eine andere Methode ausgelöst werden. Der Zustand eines Objektes wird durch die Gesamtheit der Werte aller seiner Attribute definiert. Ein Objekt ändert seinen Zustand, wenn sich der Wert mindestens eines seiner Attribute ändert (Zustandsübergang). Zwei Objekte der gleichen Klasse sind im gleichen Zustand, wenn sie in den Werten aller ihrer Attribute übereinstimmen. Um Abläufe aus der realen Welt zu simulieren, ist es notwendig, dass man sich im Vorfeld darüber klar wird, welche verschiedenen Zustände die beteiligten Objekte einnehmen können und wie diese Zustände gegebenenfalls voneinander abhängen.
Zustandsdiagramme
Mithilfe von Zustandsdiagrammen lässt sich das Verhalten von Objekten beschreiben. (Solche Objekte bezeichnet man auch als Zustandsautomaten.) Ein Zustandsübergangsdiagramm oder kurz Zustandsdiagramm besteht aus Zuständen und deren Übergängen. Es zeigt alle Abläufe, die für ein System möglich sind. Ein Zustandsübergang verbindet zwei Zustände. Der Übergang wird durch einen Pfeil dargestellt und wird stets durch ein Ereignis ausgelöst. Dieses Ereignis notiert man direkt am zugehörigen Pfeil. In einem Zustandsdiagramm gibt es genau einen Anfangszustand, der in einem Diagramm durch einen Pfeil mit rundem, ausgefülltem Pfeilfuß gekennzeichnet wird. Es sind kein, ein oder mehrere Endzustände möglich. Ein Endzustand wird durch einen kleinen ausgefüllten Kreis mit einem umschließenden Ring gekennzeichnet.
Beispiel:
Bei einer Mikrowelle führt das Öffnen der Tür zum Abbruch, das anschließende Schließen der Tür zur Wiederaufnahme des laufenden Programms. Dies lässt sich in folgendem Zustandsdiagramm darstellen. Dabei sind sowohl das auslösende Ereignis (Öffnen bzw. Schließen der Tür) als auch die ausgelöste Aktion (Abbruch bzw. Wiederaufnahme des Programms) angegeben.
Hinweise:
- Ein Übergang kann nicht unterbrochen werden. Einmal ausgelöst wird die Aktion durchgeführt.
- Ein Zustandsübergang muss den Zustand des Systems nicht unbedingt ändern.
- Ein Ereignis löst einen (oder keinen) Übergang aus, aber niemals mehrere. Man spricht in diesem Zusammenhang auch von einem deterministischen Zustandsdiagramm.
- Zustandsnamen sind frei wählbar, sollten aber selbsterklärend sein. Es ist üblich, bei der Bezeichnung von Zuständen Substantive, Partizipien oder Adjektive zu verwenden.
- Ereignisnamen enthalten hingegen immer Verben. Verben weisen darauf hin, dass ein Ereignis häufig eine Veränderung auslöst.
Folgende Fragen sind beim Entwurf eines Zustandsmodells für einen Problembereich zu klären:
- Welche Zustände sind relevant?
- Welcher Zustand ist ein Anfangszustand?
- Welche Ereignisse sind relevant?
- Welche Zustandsübergänge können ausgelöst werden?
- Gibt es Endzustände?
Beispiel für die Erstellung eines Zustandsdiagramms:
Gegeben sei ein einfacher CD-Player. Nach dem Einschalten ist das CD-Fach geschlossen. Nach dem Öffnen kann eine CD eingelegt werden und der CD-Player ist bereit zum Abspielen der CD. Mit PLAY wird die CD abgespielt, mit STOP wird die Wiedergabe abgebrochen. Der CD-Player kann entweder mit eingelegter CD oder ohne CD im Fach wieder ausgeschaltet werden.
Vorgehensweise bei der Erstellung des Zustandsdiagramms:
Zustandsübergänge mit Bedingung
Häufig ist ein Zustandsübergang mit einer Bedingung verbunden, d.h. die auszulösende Aktion wird nur dann durchgeführt, wenn eine bestimmte Bedingung erfüllt ist.
Allgemeine Darstellung eines Zustandsübergangs mit Bedingung:
Beispiel
Bei einem Getränkeautomaten kann ein Getränk erst geordert werden, wenn genug Geld eingeworfen worden ist.
Implementierung von Zustandsdiagrammen in Java
Zustandsdiagramme sind natürlich auf eine Implementierung als Programm ausgerichtet. Wir wollen uns die Vorgangsweise am Beispiel unserer Verkehrsampel aus Aufgabe 8.2.1. ansehen. Dabei sind folgende Schritte nötig:
- Für die Repräsentation der möglichen Zustände wäre zwar z. B. auch der Datentyp int geeignet, näher am Modell ist aber der Aufzählungstyp enum. Die Zustände werden so durch ihre Namen angesprochen.
- Auslösende und ausgelöste Aktionen realisiert man durch Methoden. Nur die auslösenden erhalten öffentliches Zugriffsrecht.
- Durch bedingte Anweisungen unterscheidet man, in welchem Zustand welches Ereignis ausgelöst wird.
Lösungsvorschlag für die Ampelschaltung:
public class Ampel{ //Mögliche Zustände werden als Aufzählungstyp enum vereinbart private enum Ampelzustand {rot, gruen, gelb, rotgelb, aus}; //Variable zum Aufnehmen des aktuellen Ampelzustands (Variable ist vom Typ Ampelzustand) private Ampelzustand z; public Ampel(){ //Der Konstruktor erzeugt eine Ampelinstanz im Zustand "aus" z=Ampelzustand.aus; } public void schalteEin() //auslösendes Ereignis: Aufruf der Methode schalteEin() { if (z == Ampelzustand.aus) { setzeZustand(Ampelzustand.gelb); //ausgelöste Aktion: Setzten des Ampelzustands auf "gelb" } } //Methode, die das Erscheinungsbild der Ampelzustände festlegt (hier vereinfacht durch Beschreibung auf der Konsole) private void setzeZustand(Ampelzustand zustandNeu){ z=zustandNeu; if(z==Ampelzustand.aus){ System.out.println("aus"); System.out.println("aus"); System.out.println("aus"); System.out.println(); } if(z==Ampelzustand.gelb){ System.out.println("aus"); System.out.println("gelb"); System.out.println("aus"); System.out.println(); } if(z==Ampelzustand.rot){ System.out.println("rot"); System.out.println("aus"); System.out.println("aus"); System.out.println(); } if(z==Ampelzustand.rotgelb){ System.out.println("rot"); System.out.println("gelb"); System.out.println("aus"); System.out.println(); } if(z==Ampelzustand.gruen){ System.out.println("aus"); System.out.println("aus"); System.out.println("gruen"); System.out.println(); } } //Methode für automatische Schaltung, die jeweils 3 sec (=3000 ms) Pause zwischen den Zuständen lässt public void schalteAuto(){ setzeZustand(Ampelzustand.gelb); try{Thread.sleep(3000);}catch(InterruptedException ie){/*Nichts tun*/} setzeZustand(Ampelzustand.rot); try{Thread.sleep(3000);}catch(InterruptedException ie){/*Nichts tun*/} setzeZustand(Ampelzustand.rotgelb); try{Thread.sleep(3000);}catch(InterruptedException ie){/*Nichts tun*/} setzeZustand(Ampelzustand.gruen); } }