2010-04-24 3 views
7

상태 시스템을 모델링하는 데 약간의 문제가 있습니다.C++에서 상태 시스템 설계

저는 약간의 지식 공학을 담당했으며 상태 전환뿐만 아니라 상태 전이를 결정하는 기본 결정 론적 규칙 집합을 '리버스 엔지니어링'했습니다.

나는 모범 사례에 대해 무엇을 알고 싶다 :

  • 방법 엄격 시스템이 확인되지 않은 상태에서 생을 마감 할 수 없도록 내 상태 및 상태 전환을 테스트합니다.

  • (상태 천이 요구 사항을 적용하기 위해 예를 들어,로 전환 할 수있는 상태에 대한 '지식'과 각 상태를 스며들게하기 위해, StateFooBar에 stateFoo에서 직접 예를 이동하는 것은 불가능합니다 어떻게

    .

이상적으로는 가능한 한 템플릿을 사용하여 깨끗한 패턴 기반 디자인을 사용하고 싶습니다.

어딘가에 시작해야하며 어떤 방식 으로든 포인터에 대해 감사하게 생각하고 있습니다.

+0

검색 – bobah

답변

7

Boost Statechart Library을 꼭 보시기 바랍니다.

+0

은 또한 MSM (HTTP를 살펴합니다. boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/index.html) 매우 다르다. – bobah

0

유닛 테스트를위한 초기 응용 프로그램처럼 들립니다. 많은 단위 테스트 프레임 워크가 있습니다. 나는 Boost one을 좋아한다.

1

테스트는 패턴, 템플릿 등과는 관계가 없습니다. 모든 테스트 케이스를 캡처하려면 CppUnit (xUnit 제품군의 일부)과 같은 테스트 프레임 워크를 사용하는 것이 좋습니다. 그 수는 물론 상태 머신의 복잡성에 달려 있습니다.

상태 전환 적용에 대한 질문은 상태 시스템의 클래스 디자인의 핵심입니다. 나는 한 국가가 각 국가를 자극 할 사건과 함께 전환 할 수있는 아동 국가들의 집합을 가질 것이라고 말하고 싶다. Foo 이벤트에 FooBar 자식이 없으면이 이벤트로 전환 할 수 없습니다.

Google은 "객체 지향 유한 상태 기계"를 통해 디자인 아이디어를 얻을 수 있습니다.

이와 같은 문제에 대해 생각할 때 주정부가 더 복잡한 FSM을 나타낼 수 있기 때문에 복합 디자인 패턴이이 패턴의 일부가 될 수 있다고 생각했습니다. SimpleState와 CompositeState를 구현체로 사용하는 State 인터페이스가 있습니다. 나는 다시 시작해야하고 모든 것이 잘 될 수 있는지 알아야합니다.

3

어쨌든 그렇게 복잡하지는 않습니다. 상태 머신 코드는 매우 간단하고 짧습니다.

변수에 상태를 저장합니다. myState라고 가정합니다.

상태 머신은 각 상태에 대한 코드를 실행하기 위해 myState 변수 값을 분기하는 switch 문이됩니다.나는이 제안 상태 전이 요구 사항을 적용하려면

myState = newState; 

, 당신이

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); 
} 

처럼, 대신 호출 약간의 방법을 추가해야합니다

코드는 다음과 같은 라인의 모든 것 간단하고 충분히 짧은 검사는 단위 테스트보다 더 나은 일을 할 것입니다 - 확실히 더 빠를 것입니다!

단위 테스트의 요점은 테스트 코드가 테스트 된 코드보다 간단하므로 정확성을 검사하기가 쉽고 복잡한 코드를 테스트하는 데 사용된다는 것입니다. 상태 머신 테스트 코드보다 상태 머신 코드를 확인하는 것이 더 쉽습니다. 단위 테스트가 정확한지 거의 알지 못할 때 100 % 단위 테스트 단계를보고하는 데 많은 의미가 없습니다.

다른 방법으로 말하자면, 상태 머신을 코딩하는 것이 쉽고, 올바른 것을 설계하는 것이 어렵습니다. 단위 테스트는 설계가 올바로 코딩되었는지 여부 만 알려주며, 설계가 올바른지 여부는 알려주지 않습니다.

1

상태 시스템을 사용하는 것은 때때로 발생합니다. 나는 일반적으로 ravenspoint가 제안하고 간단히 switch 문을 사용하기 때문에 수행합니다. 그러나 국가가 너무 크지 않은 경우에만 작동합니다. 이건 네 사건 같아. 이를 고려해 볼 때 가장 좋은 방법은 당신이하고 싶은 일들을 허용 할 수있는 훌륭한 아키텍처부터 시작하는 것입니다. 나는 두피모의 제안을 받아서 구글을 시도했다. 이 신문은 재미있어 보였다 - Object-Oriented State Machines. 잔인 할 수도 있지만 CppUnit 같은 것으로 테스트하기 쉬운 프레임 워크를 제공 할 것이라고 생각합니다. 당신이 고전적인 GOF 디자인 패턴 상태 머신 패턴을 찾고 있다면 Google 검색에서

일부 다른 좋은 참조

A Finite State Machine Framework

Object-Oriented Finite State Machines

0

wikipedia 봐.

Java 예제에서이 페이지 (작성 당시)를보십시오.

이 예제에는 StateContext 클래스가 있는데, 예제 사용법에서 알 수 있듯이 writeName 메소드에 대해 알고있는 클라이언트가 있습니다. 구현은 다음과 같습니다. this.myState.writeName(this, name); 이는 호출을 현재 상태로 전달하고 자신을 첫 번째 인수로 전달 함을 의미합니다.

이제 interface State을 보면, 위의 사용법과 일치하는 writeName 방법이 있습니다. StateAStateB을 모두 보게되면 컨텍스트로 돌아가서 새 상태를 설정합니다.

바로 여기에 대부분의 주립 패턴이 있습니다. 실현할 수있는 유일한 점은 StateContext 클래스가 현재 상태에 대한 참조 (C++의 포인터 여야 함)를 포함하여 조작에 관련된 모든 데이터를 보유 할 수 있다는 것입니다. 모든 주에서는 모든 동작을 집합 적으로 보유하지만 은 아니요 데이터가 아니라 데이터 (더하기 도우미 메소드)가 컨텍스트에서 지연됩니다.

상태 시스템을 개발할 때 (보통 TDD를 사용하고 있습니다) 상태 전환 테스트를 거치지 않고 원하는대로 최종 동작을 테스트합니다.