Hi zusammen. Hab vor kurzem eine Statemachine programmiert und mir dann ein paar Gedanken dazu gemacht. Hier meine Ausführungen: Sind Statemachines gut oder schlecht oder veraltet oder einfach nur eine Art zu programmieren. Wenn man Statemachines in C programmiert kann man das meines Wissens nach mit nem Pointer, mit ner Variablen oder dem goto Befehl machen. In jedem C-Buch ließt man allerdings, dass man den goto-Befehl vermeiden soll. - Wegen der linearen Programmierung. Die Herren Nassi und Shneiderman weisen darauf hin, dass Spaghetti-Code total out ist und man nur einen Ein- und einen Ausgang pro Funktionsblock haben soll. Sind Statemachines jetzt nur für bestimmte Anwendungen sinnvoll? Wenn ja, welche sind das? Kleine Programme wo nur bestimmte Zustände erreicht werden können? Oder gibts auch mega-große Statemachines oder machen die eben wieder keinen Sinn? Würde mich freuen ein paar Meinungen zu hören. Schönen Abend.
Eine state machine - oder auch Zustandsautomat - ist keine Art zu programmieren, sondern ein Modell welches sich mathematisch exakt formuliert ist. Ob Du das in deinem Programm mit Pointern oder mit whatever implementierst ist völlig egal. In der Praxis eignet sich dies eher für kleinere Anwendungsfälle. Versuch mal einen Zustandsautomaten für eine Aufzugsteuerung zu entwickeln. - Zwei Aufzüge - 10 Stockwerke mit Tasten zum Holen des Aufzugs (jeweils nach unten und nach oben) - tasten für die Wahl der Stockwerke in den Aufzügen - Aufzugtür offen/zu - Position des Aufzugs - Fahrtrichtung des Aufzugs - usw. usw. Da stößt Du recht schnell an die praktischen Grenzen, da die Anzahl der möglichen Zustände schon sehr sehr groß wird.
> Versuch mal einen Zustandsautomaten für eine Aufzugsteuerung zu > entwickeln. Ich denke, gerade für eine Aufzugssteuerung ist eine State-Maschine eine sehr gute Lösung. Das macht man dann aber nicht mehr per Hand, sondern mit professionellen Werkzeugen, welche den C-Code für die State-Maschine aus einer grafischen Darstellung für Dich generieren. Diese Werkzeuge können meines Wissen nach eine Menge Tests an der State-Maschine vornehmen, z.B, ob alle States besucht werden können, oder ob es einen Zustand gibt, der nicht mehr verlassen werden kann. Eine Steuerung für einen Aufzug ist hochgradig sicherheitsrelevant, Du möchtest wahrscheinlich auch nicht aufgrund eines Software Fehlers darin stecken bleiben. Gerade deshalb werden in solchen Fällen geprüfte Code-Generatoren eingesetzt werden, welche aus einer abstrakteren Darstellung, wie es eine FSM ist, die effektive Steuerung generieren.
sicher nicht schrieb:
> In der Praxis eignet sich dies eher für kleinere Anwendungsfälle.
Ganz im Gegenteil.
Eine Statemachine ist ein ausgezeichnetes Mittel um komplette und
komplexe reale Maschinen in den Griff zu kriegen. Gerade die Aufteilung
in States und Übergänge der States unter bestimmten Umständen und die
gute Dokumentierbarkeit des Ganzen ist es, die Statemachines so
interessant machen.
sicher nicht schrieb: > Da stößt Du recht schnell an die praktischen Grenzen, da die Anzahl der > möglichen Zustände schon sehr sehr groß wird. Dann machst du was falsch. Zb. sind in deiner Aufgabestellung die 10 Tasten für die Statemaschine des Aufzugs ziemlich irrelevant. Ob es 10 oder 20 sind, ist egal, die Statemaschine 'Aufzug' bekommt als Input 'Fahre zu Stockwerk x' und das tut sie dann auch indem sie sich im Zustand 'Stehe in einem Stockwerk und die Türen sind offen' diesen Fahrbefehl in ihre Queue der anzufahrenden Ziele einsortiert. Der nächste Zustand ist dann 'Beginn Tür schliessen', gefolgt von 'Tür geschlossen' gefolgt von 'Anfahren' gefolgt von 'Anfahren nach oben' bzw. 'Anfahren nach unten' gefolgt von 'aufhören zu beschleunigen' gefolgt von 'beginn des Abbremsens vor dem nächsten Ziel' gefolgt von 'ausrichten auf das Stockwerk' gefolgt von 'Tür öffnen anfangen' gefolgt von 'Tür ist offen' gefolgt von 'Stehe in einem Stoclwerk und die Türen sind offen'. Ob es weitere States gibt (vor allem der Fehlerfall ist immer interessant) und wie die Aufteilung in States exakt funktioniert kann von Aufzug zu Aufzug verschieden sein. Ob man die Logik, nach der das nächste Fahrziel ausgewählt wird auch in eine Statemaschine quetscht oder ob da irgendwelche Heuristiken angewendet werden oder KI oder Zeitsteuerungen kann man von Fall zu Fall entscheiden. Das tangiert aber die Statemaschine 'Aufzug' nicht. Die arbeitet stur ihren Stiefel "Fahrbefehl ausführen" mit allem was dazu nötig ist ab. Statemaschinen sind auch ein gutes Werkzeug um Multitasking Aufgaben hinzukriegen. Gerade in Maschinen ist es oft so, dass ja mehrere Vorgänge gleichzeitig ablaufen. Modelliert man jeden Vorgang mit einer eigenen Statemaschine, die im Wechsel jeweils einen Zustand abarbeiten dürfen, dann ergibt sich zwangsläufig eine Multitasking Struktur, selbst wenn die Sprache dieses Konzept überhaupt nicht unterstützt (wie zb C) und keinerlei dafür notwendige Konzepte zur Verfügung stellt.
alles State oder was schrieb: > In jedem C-Buch ließt man allerdings, dass man den goto-Befehl vermeiden > soll. - Wegen der linearen Programmierung. Nicht wegen irgendwelcher linearer Programmierung, sondern weil sonst ganz schnell FORTRAN-Code daraus entsteht, den in zwei Jahren keiner mehr pflegen kann. Für bestimmte Ausnahmebehandlungen beispielsweise kann ein goto ein nützliches Mittel sein, den Code übersichtlicher zu bekommen. Allerdings würde ich es nicht als reguläre Methode zur Implementierung einer state machine empfehlen, eben um Spaghetti-Code zu vermeiden. > Die Herren Nassi und Shneiderman weisen darauf hin, dass Spaghetti-Code > total out ist und man nur einen Ein- und einen Ausgang pro > Funktionsblock haben soll. Naja, solche Statements haben immer zwei Seiten: es ist was dran, man kann natürlich durch wildes Anbringen von return-Anweisungen in einer Funktion ein ähnliches Chaos produzieren wie mit einer planlosen Ansammlung von gotos. Auch hier gilt aber: sinnvoll benutzt, ist es ein nützliches Mittel, um die Übersichtlichkeit verbessern zu können. Schau selbst:
1 | bool func(int a, int b) |
2 | {
|
3 | bool error = true; |
4 | |
5 | if (early_error) { |
6 | /* cannot continue here */
|
7 | error = false; |
8 | } else { |
9 | if (!do_something(a, b)) { |
10 | /* another error happened */
|
11 | error = false; |
12 | } else { |
13 | if (do_something_else(a, b) < limit) { |
14 | /* out of limits */
|
15 | error = false; |
16 | } else { |
17 | do_even_more(a, b); |
18 | }
|
19 | }
|
20 | }
|
21 | return error; |
22 | }
|
1 | bool func(int a, int b) |
2 | {
|
3 | if (early_error) { |
4 | /* cannot continue here */
|
5 | return false; |
6 | |
7 | if (!do_something(a, b)) { |
8 | /* another error happened */
|
9 | return false; |
10 | |
11 | if (do_something_else(a, b) < limit) |
12 | /* out of limits */
|
13 | return false; |
14 | |
15 | do_even_more(a, b); |
16 | |
17 | return true; |
18 | }
|
Welche Implementierung kann man besser lesen?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.