Arbeiten mit Zustandsdiagrammcode
Die übergeordnete Klasse des Zustandsdiagramms (d.h. die "Controller-Klasse" oder "Kontextklasse") bildet die einzige Schnittstelle zwischen dem Benutzer des Zustandsdiagramms und der Zustandsdiagrammimplementierung.
Die Controller-Klasse bietet Methoden, mit Hilfe derer die Zustandsdiagramme von "außen" her geändert werden können (z.B. nachdem externe Ereignisse eingetreten sind).
Bei der Implementierung des Zustandsdiagramms werden dagegen Controller-Klassenmethoden ("Callbacks") aufgerufen, um den Benutzer des Zustandsdiagramms über Zustandsänderungen (OnEntry, OnExit, ...), Transitionseffekte und die Möglichkeit Methoden für Bedingungen (Guards) außer Kraft zu setzen und zu implementieren, zu informieren.
UModel kann einfache Operationen (ohne Parameter) für Entry/Exit/Do-Verhalten, Transitionseffekte, ...automatisch erstellen, wenn die entsprechende Option aktiviert ist. (siehe auch Erstellen von Zuständen, Aktivitäten und Transitionen). Diese Methoden können in UModel beliebig (durch Hinzufügen von Parametern, Definieren der Parameter als abstrakt, usw.) geändert werden.
Ein Zustandsdiagramm (d.h. seine Controller-Klasse) kann mehrmals instantiiert werden. Alle Instanzen sind unabhängig voneinander.
•Die Ausführung des UML-Zustandsdiagramms ist für das Modell: Bis zur Fertigstellungen ausführen" konzipiert.
•UML-Zustandsautomaten gehen davon aus, dass jedes Ereignis abgeschlossen ist, bevor das nächste verarbeitet wird.
•Dies bedeutet auch, dass keine Entry/Exit/Do-Aktion oder kein Transitionseffekt eine neue Transition/eine Zustandsänderung direkt auslösen darf.
Initialisierung
•Jede Region eines Zustandsdiagramms muss einen Anfangszustand haben.
•Der von UModel generierte Code initialisiert alle Regionen des Zustandsdiagramms automatisch (oder bei Aufruf der Initialize()-Methode der Controller-Klasse).
•Wenn OnEntry-Ereignisse bei der Initialisierung nicht erwünscht sind, können Sie die Initialize()-Methode manuell aufrufen und OnEntry-Ereignisse beim Start ignorieren.
Abrufen des/der aktuellen Zustands/Zustände
UModel unterstützt sowohl zusammengesetzte Zustände als auch orthogonale Zustände, d.h. es gibt nicht nur einen aktuellen Zustand, sondern jede Region (auf jeder hierarchischen Ebene) kann einen aktuellen Zustand haben.
Im Beispiel "AirCondition" wird gezeigt, wie die Regionen des aktuellen Zustands / der aktuellen Zustände durchlaufen werden.
TreeNode rootNode = m_CurrentStateTree.Nodes.Add(m_STM.getRootState().getName());
UpdateCurrentStateTree(m_STM.getRootState(), rootNode);
private void UpdateCurrentStateTree(AirCondition.AirConditionController.IState state, TreeNode node)
{
foreach (AirCondition.AirConditionController.IRegion r in state.getRegions())
{
TreeNode childNode = node.Nodes.Add(r.getName() + " : " + r.getCurrentState().getName());
UpdateCurrentStateTree(r.getCurrentState(), childNode);
}
}
Beispiel 1 - eine einfache Transition
Die entsprechende Operation wird in UModel automatisch generiert.
Generierte Methode im Code:
private class CTestStateMachine : IState |
•Der Benutzer des Zustandsdiagramms sollte die generierte Methode "MyEvent1" aufrufen, wenn das entsprechende Ereignis (außerhalb des Zustandsautomaten) eintritt.
•Der Rückgabeparameter dieser Ereignismethoden liefert Informationen, ob das Ereignis eine Zustandsänderung verursacht hat (d.h. ob es eine Auswirkung auf das Zustandsdiagramm hat) oder nicht. Wenn sich der Automat z.B. im "State1" befindet und "MyEvent1()" eintritt, so ändert sich der aktuelle Status in "State2" und "MyEvent1()" gibt "true" zurück. Wenn "State2" aktiv ist und "MyEvent1()" eintritt, ändert sich nichts am Zustandsdiagramm und MyEvent1() gibt "false" zurück.
Beispiel 2 - eine einfache Transition mit einem Effekt
Die entsprechende Operation wird in UModel automatisch generiert.
Generierte Methode im Code:
private class CTestStateMachine : IState |
•"OnState1State2Effect()" wird immer dann von der Zustandsdiagrammimplementierung aufgerufen, wenn die Transition zwischen "State1" und "State2" ausgelöst wird.
•Als Reaktion auf diesen Effekt sollte "OnState1State2Effect()" in einer abgeleiteten Klasse von "CTestStateMachine" außer Kraft gesetzt werden.
•"CTestStateMachine:: OnState1State2Effect()" kann auch auf "abstract" gesetzt werden und Sie erhalten Kompilierfehler bis die Methode außer Kraft gesetzt wird.
•Wenn "OnState1State2Effect()" nicht "abstract" ist und die Option "Debug-Meldungen generieren" aktiv ist, generiert UModel die folgende Debug-Ausgabe:
// Override to handle entry/exit/do actions, transition effects,...: |
Beispiel 3 - eine einfache Transition mit einem Effekt-Parameter
Die entsprechende Operation wird in UModel automatisch generiert.
Generierte Methode im Code:
private class CTestStateMachine : IState |
•Zur Durchführung von (automatisch mit UModel erzeugten) Operationen können Parameter manuell hinzugefügt werden (UModel kann nicht wissen, welcher Typ benötigt wird).
•In diesem Beispiel wurde der Parameter "text:String" zur Effekt-Methode in TestController hinzugefügt. Beim Aufruf dieser Methode muss ein ordnungsgemäßes Argument definiert werden (hier: "1 => 2").
•Eine andere Möglichkeit wäre z.B. die folgende: Aufruf von statischen Methoden ("MyStatic.OnState1State2Effect("1 => 2")") oder Methoden von Singletons ("getSingleton().OnState1State2Effect("1 => 2")").
Beispiel 4 - entry/exit/do-Aktionen
Die entsprechenden Operationen werden in UModel automatisch generiert.
Generierte Methode im Code:
private class CTestStateMachine : IState |
•Zustände können entry/exit/do-Verhalten aufweisen. UModel generiert automatisch die entsprechenden Operationen zu deren Behandlung.
•Wenn im Beispiel oben "MyEvent2()" eintritt, ruft die Zustandsdiagrammimplementierung "OnExitState3()" auf. Wenn "MyEvent2" einen Effekt hätte, würde dieser in der Folge aufgerufen werden. Anschließend würden "OnEntryState4" und "OnDoState4" aufgerufen werden.
•Normalerweise sollten diese Methoden außer Kraft gesetzt werden. Wenn sie nicht abstrakt sind und die Option "Debug-Meldungen generieren" aktiv ist, liefert UModel eine Standard-Debug-Ausgabe, wie in Beispiel 2 beschrieben.
•Diese Methoden können auch Parameter haben, wie in Beispiel 3 gezeigt.
Beispiel 5 - Guards
Transitionen können Guards (Wächterausdrücke) haben, die ermitteln, ob die Transition wirklich ausgelöst werden kann.
Die entsprechende Operation wird in UModel automatisch generiert.
Generierte Methode im Code:
private class CTestStateMachine : IState |
•Wenn "State5" der aktive Zustand ist und "MyEvent2" eintritt, so ruft die Zustandsdiagrammimplementierung "CanGoState6" auf und je nach Ergebnis wird die Transition ausgelöst oder nicht.
•Normalerweise sollten diese Methoden außer Kraft gesetzt werden. Wenn sie nicht abstrakt sind und die Option "Debug-Meldungen generieren" aktiv ist, liefert UModel eine Standard-Debug-Ausgabe, wie in Beispiel 2 beschrieben.
•Diese Methoden können auch Parameter haben, wie in Beispiel 3 gezeigt.
•Es sind mehrere Transitionen mit demselben Ereignis aber unterschiedlichen Guards möglich. Die Reihenfolge, in der die verschiedenen Guards abgefragt werden, ist nicht definiert. Wenn eine Transition keinen Guard hat oder der Guard "else" ist, wird sie als der letzte Guard betrachtet (d.h. dieser Guard wird nur dann ausgelöst, wenn alle anderen Transitions-Guards "false" zurückgeben). So ist z.B. im Diagramm unten nicht definiert, ob CanGoState6() oder CanGoState7() zuerst aufgerufen wird. Die dritte Transition wird nur ausgelöst, wenn CanGoState6() und CanGoState7() false zurückgeben.
Weitere Konstrukte und Funktionalitäten finden Sie in den Beispielen AirCondition.ump und Complex.ump.