2010-04-24 19 views
7

Mam mały problem, który wymaga modelowania maszyny stanu.Projektowanie maszyny stanu w C++

Udało mi się zrobić trochę inżynierii wiedzy i "inżynierii wstecznej" zestaw prymitywnych reguł deterministycznych, które określają stan, a także przejścia stanu.

Chciałbym wiedzieć co najlepsze praktyki dotyczące:

  • Jak testuje swoje stany i przejścia między stanami, aby upewnić się, że system nie może skończyć się w stanie nieustalonym.

  • Jak egzekwować wymagania zmiana stanu (na przykład, powinno być możliwe, aby przejść bezpośrednio z stateFoo do StateFooBar, czyli nadać każdy stan z „wiedzy” o stanach może przejście do.

Idealnie chciałbym użyć czystego, opartego na wzorach projektu, z szablonami, gdzie tylko to możliwe

Potrzebuję gdzieś zacząć, a ja byłbym wdzięczny za wszelkie wskazówki (gra słów nie przeznaczonych), które są wysyłane na mój sposób.

+0

wyszukiwania dla „formalnego zatwierdzania machiny państwowej” – bobah

Odpowiedz

7

Pamiętaj, aby spojrzeć na Boost Statechart Library.

+0

biorą również do obejrzenia MSM (http: // www. boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/index.html), są bardzo różne. – bobah

0

Brzmi jak nieskazitelna aplikacja do testowania jednostkowego. Istnieje wiele frameworków testów jednostkowych. Tak się składa, że ​​podoba mi się Boost one.

1

Testowanie ma niewiele wspólnego z wzorcami, szablonami itp. Poleciłbym szkielet testowy, taki jak CppUnit (część rodziny xUnit) do przechwytywania wszystkich przypadków testowych. Oczywiście liczba ta będzie zależeć od złożoności maszyny stanów.

Twoje pytanie dotyczące egzekwowania przejść między stanami stanowi podstawę do zaprojektowania klasy dla twojego automatu stanów. Powiedziałbym, że stan będzie miał kolekcję stanów potomnych, do których może przejść, wraz ze zdarzeniem, które wyzwoli każdego z nich. Jeśli wydarzenie Foo nie ma elementu potomnego FooBar, nie ma możliwości przejścia do niego.

Chciałbym, aby Google "zorientowane obiektowo skończone maszyny stanów" zaczęły otrzymywać pewne pomysły na projekty.

Kiedy myślałem o takich problemach, pomyślałem, że wzór kompozytowy może być jego częścią, ponieważ państwo może reprezentować bardziej złożony FSM. Będę miał interfejs stanu, z SimpleState i CompositeState jako implementacje. Musiałbym zacząć od nowa i zobaczyć, czy to wszystko może się udać.

3

Ojej, to nie jest tak skomplikowane, jak się wydaje. Kod maszynowy stanu jest bardzo prosty i krótki.

Zapisz stan w zmiennej, powiedzmy myState.

Maszyna stan będzie instrukcją przełącznika, rozgałęziającą się na wartość zmiennej myState w celu wykonania kodu dla każdego stanu.

Kod będzie pełen liniami takimi jak ten:

myState = newState; 

Aby egzekwować wymagania zmiana stanu, trzeba dodać trochę metodę o nazwie zamiast, jak to

void DoSafeStateTransition(int newState) 
{ 
// check myState -. newState is not forbidden 
// lots of ways to do this 
// perhaps nested switch statement 

switch(myState) { 

… 

case X: switch(newState) 
    case A: case B: case Z: HorribleError(newState); 
    break; 

... 

} 

// check that newState is not undetermined 

switch(newState) { 

// all the determined states 
case A: case B: case C … case Z: myState = newState; break; 
default: HorribleError(newState); 
} 
} 
void HorribleError(int newState) 
{ printf("Attempt to go from %d to %d - disallowed\n", 
     myState, newState); 
    exit(1); 
} 

I sugerują, że to proste i wystarczająco krótkie, aby inspekcja przebiegła lepiej niż testowanie jednostkowe - na pewno będzie dużo szybciej!

Punktem, według mnie, testów jednostkowych jest to, że kod testowy jest prostszy niż testowany kod, więc można go łatwiej sprawdzić pod kątem poprawności, a następnie użyć go do przetestowania skomplikowanego kodu. Często łatwiej jest sprawdzić kod maszynowy stanu niż kod testu stanu komputera. Nie ma sensu zgłaszanie 100-procentowego testu jednostkowego, jeśli nie masz pojęcia, czy testy jednostkowe są poprawne.

Innymi słowy: kodowanie maszyny stanowej jest łatwe, a zaprojektowanie prawidłowego jest trudne. Testy jednostkowe podpowiedzą tylko, czy poprawnie zakodowałeś projekt, a nie czy projekt był poprawny.

1

Korzystanie z automatów stanów jest czymś, co pojawia się od czasu do czasu. Zwykle robię to, co sugeruje ravenspoint i po prostu dokonuję instrukcji zmiany. Ale to działa tylko wtedy, gdy państwa nie są zbyt duże. Ten rodzaj brzmi jak twoja sprawa. Biorąc to pod uwagę, myślę, że najlepszą rzeczą jest zacząć od dobrej architektury, która pozwoli na pewne rzeczy, które chcesz robić. Wziąłem sugestię duffymo i wypróbowałem Google'a. Ten artykuł wyglądał interesująco - Object-Oriented State Machines. To może być przesada, ale myślę, że da to ramy, które będą łatwe do przetestowania za pomocą czegoś takiego jak CppUnit.

Niektóre inne dobre referencje z wyszukiwarki Google

A Finite State Machine Framework

Object-Oriented Finite State Machines

0

Jeśli szukasz dla klasycznych wzorcach GOF konstrukcji maszyn State wzór, a następnie spójrz na wikipedia.

Spójrz na tę stronę (w chwili pisania) na przykładzie Java.

Ma klasę StateContext, którą można zobaczyć na przykładzie użycia, ma klientów, którzy wiedzą o metodzie writeName. Implementacja to: this.myState.writeName(this, name);, co oznacza, że ​​przekazuje połączenie do bieżącego stanu, podając się jako pierwszy argument.

Teraz spójrz na interface State, ma on metodę writeName, która pasuje do powyższego zastosowania. Jeśli spojrzysz zarówno na StateA jak i StateB, wywołują one powrót do kontekstu ustawiając nowy stan.

To większość wzoru państwowego właśnie tam. Jedyną rzeczą, o której należy pamiętać, jest to, że klasa StateContext może przechowywać wszystkie dane związane z jej działaniem, w tym odniesienie (musi to być wskaźnik w C++) do bieżącego stanu. Wszystkie stany łącznie zachowują wszystkie dane, ale odradzają dane (plus metody pomocnicze) w kontekście.

Kiedy pracuję nad maszyną stanów (zwykle używam TDD), nie przejmuję się testowaniem przejść między stanami, tylko że ostateczne zachowanie jest takie, jak chcę.