Zustände umsetzen Enumerations (Aufzählungen) Zustandsobjekte Dr. Beatrice Amrhein
Kursinhalt Aufzählungen erzeugen Aufzählungen verwenden Zustandsobjekte erzeugen Zustandsobjekte verwenden Nach dem Handbuch der.net 4.0-Programmierung, Rolf Wenger, 2012 2
Enumerations Aufzählungen 3
Definition: Aufzählungen (Enumerations) Eine Aufzählung (Enumeration) bietet eine effiziente Möglichkeit, einen Satz benannter Konstanten (vom Typ int) zu definieren. Das Schlüsselwort zum definieren einer Aufzählung heisst enum. Beispiel: Sie sollen eine Variable Wochentag definieren. Es gibt nur sieben sinnvolle Werte, die diese Variable speichern kann. Um diese Werte zu definieren, verwenden Sie darum statt eines int-typs eine Aufzählung. enum Wochentag Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag}; 4
Der Vorteil von Aufzählungen Es ist eindeutig, welche Werte für diese Variable gültig sind. Es kann keine Fehlbelegungen geben (es können nur gültige Wochentage ausgewählt werden) In Visual Studio führt IntelliSense die gültigen Werte automatisch auf. 5
Zustände In einem Zustandsdiagramm gibt es eine endliche Anzahl von Zuständen. Diese werden oft als Enumeration implementiert. 6
Zustände als Enumeration enum Bancomat }; AmAufstarten, AmFehlerAnzeigen, Bereit, AmKartePrüfen, AmPincodePrüfen, AmKarteAusgeben, AmGeldAusgeben 7
Zwei Beispiele von Aufzählungen Aufzählungen für Wochentag und Monat enum Wochentag Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag }; enum Monat Januar, Februar, März, April, Mai, Juni, Juli, August, September, November, Dezember }; 8
Werte von Aufzählungen Den Zuständen können auch Nummern vergeben werden: enum Wochentag Sonntag = 0, Montag = 1, Dienstag = 2, Mittwoch = 3, Donnerstag = 4, Freitag = 5, Samstag = 6 }; enum Monat Januar = 1, Februar = 2, März = 3, April = 4, Mai = 5, Juni = 6, Juli = 7, August = 8, September = 9, Oktober = 10, November = 11, Dezember = 12 }; enum Farbe Rot = 15, Blau = 22, Grün = 32, Gelb = 64, Schwarz = 0, Weiss = 100 }; Nach dem Handbuch der.net 4.0-Programmierung, Rolf Wenger, 2012 9
Werte von Aufzählungen Damit können Werte von Aufzählungen auch verglichen werden: enum Wochentag Sonntag = 0, Montag = 1, Mittwoch = 3, Donnerstag = 4, Freitag = 5, Samstag = 6 }; static void Main(string[] args) if (Wochentag.Sonntag < Wochentag.Mittwoch) Console.WriteLine("Sonntag ist vor Mittwoch"); } else Console.WriteLine("Sonntag ist nach dem Mittwoch"); } } if (Wochentag.Donnerstag < Wochentag.Mittwoch) Console.WriteLine("Donnerstag ist vor Mittwoch"); } else Console.WriteLine("Donnerstag ist nach dem Mittwoch"); } Console.ReadLine(); Nach dem Handbuch der.net 4.0-Programmierung, Rolf Wenger, 2012 10
Werte von Aufzählungen static void Main(string[] args) if (Farbe.Rot < Farbe.Blau) Console.WriteLine("Rot ist heller als Blau"); } else Console.WriteLine("Rot ist dunkler als Blau"); } if (Farbe.Gelb < Farbe.Rot) Console.WriteLine("Gelb ist heller als Rot"); } else Console.WriteLine("Gelb ist dunkler als Rot"); } } Console.ReadLine(); enum Farbe Rot = 15, Blau = 22, Grün = 32, Gelb = 4, Schwarz = 100, Weiss = 0 }; Nach dem Handbuch der.net 4.0-Programmierung, Rolf Wenger, 2012 11
Aufzählungen verwenden 12
Noten A bis F Gültige Noten sind Buchstaben A bis F plus die Note FX. Das gibt die folgende Aufzählung public enum Note A, B, C, D, E, FX, F } Diese kann in einer Klasse Bewertung verwendet werden: public class Bewertung public enum Note A, B, C, D, E, FX, F } } public static Note getleistung(int prozent)... } public static String Ausgabe(Note n)... } 13
Berechnung der Note Aus der Prozent-Zahl lässt sich die Note wie folgt berechnen: public static Note getleistung(int prozent) Note resultat; if (prozent >= 90) resultat = Note.A; } else if (prozent >= 80) resultat = Note.B; } else if (prozent >= 70) resultat = Note.C; } else if (prozent >= 60) resultat = Note.D; } else if (prozent >= 50) resultat = Note.E; } else if (prozent >= 35) resultat = Note.FX; } else resultat = Note.F; } } return resultat; 14
Entscheidungen mit Hilfe von Aufzählungen Eine Aufzählung kann in einem switch-case Statement für die Auswahl verwendet werden: public enum Note A, B, C, D, E, FX, F } public static String getleistung(note ects) String resultat; switch (ects) case Note.A: restultat = "Hervorragend"; break; case Note.B: restultat = "Sehr gut"; break; case Note.C: restultat = "Gut"; break; case Note.D: restultat = "Passabel"; break; case Note.E: restultat = "Passabel"; break; case Note.F: restultat = "Ungenügend"; break; } return resultat; } 15
Zustandsdiagramm mit Hilfe von Enumerations implementieren 16
Zustandsdiagramm Implementieren Dieses Zustands- Diagramm hat 8 Zustände. Dies können wir mit einer Enumeration auflisten: enum BilletAutomat AmAufstarten, FehlerAnzeige, Bereit, AmBearbeiten, StartOrtEinlesen, ZielortEinlesen, BilletTypEinlesen, BarBezahlen, AmDrucken, Ausgabe }; 17
Zustandsdiagramm Implementieren Das Zustandsdiagramm hat nur die zwei Übergangs-Ereignisse Weiter( ) und Fehler( ). Ausserdem haben alle Zustände ein entry- Ereignis. 18
Zustandsdiagramm implementieren Die Zustandsübergänge des Zustandsdiagramms können mit Hilfe der Enumerations implementiert werden. Die Zustands-Maschine implementiert für jedes Übergangs-Ereignis die entsprechende Methode. Für jeden Zustand wird der Nachfolgezustand für das Übergangs-Ereignis (hier Weiter) definiert und die entry-methode des Nachfolgezustands ausgeführt. public void Weiter() Das Ereignis Weiter() führt zum Nachfolgezustand Bereit. switch (automat.zustand) Die Entry-Methode von Bereit erzeugt ein neues Fenster. Dann kann der Übergang case Zustand.AmAufstarten: (nächsterschritt) ausgeführt werden. automat.zustand = Zustand.Bereit; automat.newwindow = new BereitView(automat); automat.nächsterschritt(); break;... 19
Zustandsdiagramm implementieren Übergangs-Ereignis Weiter() für alle Zustände implementieren: public void Weiter() switch (automat.zustand) Für jeden Zustand wird der Nachfolgezustand für das Ereignis Weiter() case Zustand.AmAufstarten: definiert und die entry-methode des automat.zustand = Zustand.Bereit; Nachfolgezustands ausgeführt. automat.newwindow = new BereitView(automat); automat.nächsterschritt(); break; case Zustand.Bereit: automat.zustand = Zustand.AmKartePrüfen; automat.newwindow = new KartePrüfenView(automat); automat.nächsterschritt(); break; case Zustand.AmKartePrüfen: automat.zustand = Zustand.AmPincodeEinlesen; automat.newwindow = new PincodeView(automat); automat.nächsterschritt(); break;... 20
Zustandsdiagramm implementieren Analog wird die zweite Methode für das zweite Übergangs-Ereignis Fehler() implementiert. public void Fehler(string meldung) automat.fehlermeldung = meldung; switch (automat.zustand) case Zustand.AmAufstarten: automat.zustand = Zustand.AmFehlerAnzeigen; automat.newwindow = new FehlerView(automat); automat.nächsterschritt(); break; case Zustand.AmGeldbetragEinlesen: automat.zustand = Zustand.AmFehlerAnzeigen; automat.newwindow = new FehlerView(automat); automat.nächsterschritt(); break; case Zustand.AmKartePrüfen: automat.zustand = Zustand.AmFehlerAnzeigen; automat.newwindow = new FehlerView(automat); automat.nächsterschritt();... Für jeden Zustand wird der Nachfolgezustand für das Ereignis Fehler(meldung) definiert und die entry-methode des Nachfolgezustands ausgeführt. 21
Beispiel Bancomat Den vollständigen Zustandsautomaten des Bancomat Beispiels finden Sie im Verzeichnis BancomatEnumeration.zip der Übung12. 22
Zustands-Objekte 23
Nachteile von Zustands-Maschinen mit Enumerations Die Implementation mit Enumerations ist für kleine Zustandsdiagramme gut machbar. Für grössere Zustandsdiagramme hat diese Variante aber Nachteile: Die Methoden für die Übergangsereignisse (switch-case) werden sehr kompliziert. Die Implementation ist unflexibel. Beim Einführen eines neuen Zustandes müssen alle Methoden korrigiert werden. Die Fehlersuche in so komplexen Methoden ist schwierig. Die Zustände werden nicht eins-zu-eins abgebildet, sie verschwinden in der Zustands-Maschine. Komplexe Zustände und Unterzustände können nur schwierig umgesetzt werden. 24
Implementation mit Zustands-Objekten Ein Zustandsobjekt o kennt selber seine Übergangsereignisse o Implementiert selber seine entry-, do- und exit-ereignisse o Kennt seine Nachfolgezustände Da jedes Zustandsobjekt nur seine eigene Umgebung kennen muss, ist die Implementation recht einfach. 25
Zustands-Objekt Zustand AmAufstarten o Der Zustand AmAufstarten hat zwei Nachfolgezustände: Bereit bei Weiter() und AmFehlerAnzeigen bei Fehler(). o Ausserdem hat es ein entry-ereignis. public void Weiter() Bereit zustand = new Bereit(automat); automat.zustand = zustand; } public void Fehler(String meldung) automat.fehlermeldung = meldung; AmFehlerAnzeigen fehler = new AmFehlerAnzeigen(automat); automat.zustand = fehler; } 26
Zustands-Objekt Zustand AmAufstarten o Beim Eintritt in den Zustand AmAufstarten muss das entsprechende Fenster angezeigt werden. private Automat automat; // der Bancomat, zu dem diese Zustände gehören public AmAufstarten(Automat a) this.automat = a; AufstartenView view = new AufstartenView(automat); automat.nextwindow(view); } 27
Vollständige Implementation Statt der Aufzählung (Enumeration) braucht es für die Implementation des Zustandsdiagramms je ein Zustandsobjekt für jeden Zustand. Dieses ist nur für seine eigene, lokale Umgebung (Nachfolge-Zustände und Übergangsereignisse) zuständig. IZustand ist die Schablone, welche vorgibt, was für Methoden implementiert werden müssen. 28