자식 상태 머신이 어떻게 컨트롤을 부모 상태 머신으로 되돌릴 수 있습니까?


9

내 최상위 상태 시스템에는 몇 가지 상태와 가장자리가 있습니다. 이것을 부모 상태 머신이라고합니다.

A ----> B ----> C

상위 상태 시스템 내의 모든 상태도 상태 시스템 일 수 있습니다. 이 아이들 상태 머신이라고 부를 것입니다.

           ___________
         /            \
A ----> |  B0->B1->B2  | ----> C
         \____________/

상위 상태 머신이 A에서 B로 전환되면 B의 상태 머신이 대신합니다. B가 실행을 마치면 어떻게 부모 상태 머신에 대한 제어권을 포기하고 상태 C로 전환해야합니까? 어떤 디자인 패턴을 사용하십니까?

궁금한 점이 있다면 정확한 프로젝트가 상당히 복잡하고 자식 상태의 내부 작업을 캡슐화하는 것이 자연 스럽기 때문에 부모 상태 머신 내에 자식 상태 머신이 있습니다.


B0, B1 및 B2는 외부 세계가 단일 단위로 간주하는 요소의 구성 요소라는 것을 알아야합니다. 따라서 B0, B1 및 B2가 포함 된 MachineContainer클래스 가 있어야하며 BB2가 끝나면 컨테이너로 제어권을 다시 전달한 다음 C로 전환합니다. 흥미로운 문제입니다!
FrustratedWithFormsDesigner

2
귀하의 질문에 분명한 답변이 있거나 귀하의 질문이 명확하지 않습니다. 부모의 관점에서, 자식 상태 머신이없는 상태 머신을 구현하는 것과 똑같이 구현해야합니다. 자식 상태 머신을 사용하여 상태가 구현되지만 부모에게는 전혀 영향을 미치지 않습니다. 또한 종료시 상위 레벨 이벤트 만 생성하는 것 이외의 하위 상태 머신에는 영향을 미치지 않아야합니다.
Dunk

답변:


5

모든 상태 머신에는 일종의 이벤트 핸들러와 해당 이벤트를 트리거하는 수단이 있습니다. 해당 핸들러는 기존 상태 및 이벤트 유형을 입력으로 사용하고 새 상태를 선택하며 선택적으로 부작용 코드를 실행합니다.

기본적으로 B주 이벤트 핸들러는 이벤트 핸들러로 인식하지 않고 B상태를 유지 하는 이벤트를 전달합니다 B. 때 B전환하고 싶어 C, 그것은 메인 이벤트 핸들러에 적절한 이벤트를 보냅니다.


2

당신이 읽고 Taoup의이 섹션을 ? 이를 수행하는 여러 가지 방법이 있지만 그 중 다수는 상태 머신을 분할 한 방법에 따라 다릅니다 . 별도의 프로세스입니까? 실? 사물?

그것들을 어떻게 구축했는지 파악하고, 그들이 의사 소통을 할 수있는 표준적인 방법이 있는지 살펴보십시오. 존재하지 않는 경우 시스템을 잘못 설계 한 것일 수 있습니다.

나를 위해 stdin과 stdout을 연결하는 별도의 프로세스를 살펴 보겠습니다. 그런 다음 자식 상태 시스템은 독립형이되어 stdin에서 작동하고 stdout에서 출력합니다. 자식 프로세스를 시작하고 파이프를 연결 한 다음 데이터를 덤프하고 결과를 기다리는 것이 부모 상태 시스템의 작업이됩니다. 이 모든 것들이 이미 모든 현대 언어로 이루어 졌으므로 쉽게 할 수 있습니다.


1

두 상태 머신을 분리하고 그 사이에 메시지 전달을 사용하십시오. 따라서 상태 머신 1은 ABC에서 진행하며 상태 B에서는 상태 머신 2의 현재 결과를 확인합니다. 출력이 변경되면 상태 머신 1이이를 인식 할 수 있으며 상태 머신 2는 인식 할 필요가 없습니다. 상태 머신 1이 실제로 작동하는 방식 다음과 같은 것 :

typedef struct StateMachine {
  void(*Update)(); // function to update the state machine
  int Data;        // generic temp holder to survive state contexts
  int State;       // current state of our state machine
  int *Message;    // pointer to a shared integer for message passing
};

int main(void) {
  int Message = 0;
  /* NewStateMachine would malloc the struct, pass in the int reference
   * and function pointer as well as add it to a circularly linked list */
  NewStateMachine(&Message, MainLoop);
  NewStateMachine(&Message, MinorLoop);
  StateMachine *Current = StateMachine_CLL.First;

  for(;;) {
    Current->Update(Current); /* Update the current state machine */
    Current = Current->Next;  /* And the advance to the next one */
  }
}

void MainLoop(StateMachine *this) {
  switch(this.State) {
  case 0:
    CloseCoolantTank(1); /* safe to call if valve already closed */
    CloseCoolantTank(2); /* safe to call if valve already closed */
    this.State = 1;
    break;
  case 1:
    /* we have a message, do something */
    if(*this.Message) this.State = 2;          
    /* otherwise stall at this state until we get a message */
    else this.State = 1;          
    break;
  case 2:
    if(*this.Message == 1) this.State = 3;      /* warm */
    else if(*this.Message == 2) this.State = 4; /* hot! */
    else this.State = 0;                        /* cooled down, shut off valves */
    this.Message = 0;                           /* clear the message */
    break;
  case 3:
    OpenCoolantTank(1); /* opens the valve, safe to call if already open */
    this.State = 2;     /* recheck for new message */
    break;
  case 4:
    OpenCoolantTank(2); /* opens the valve, safe to call if already open */
    this.State = 3;     /* also open coolant tank 1 for extra cooling */
    break;
  }
}

/* Monitor temperature and send messages on overheat */
void MinorLoop(StateMachine *this) {
  switch(this.State) {
  case 0:
    this.Data = ReadADCValue();
    this.State = 1;
    break;
  case 1:
    if(this.Data > 150) *this.Message = 2;
    else if(this.Data > 100) *this.Message = 1;
    this.State = 0;
    break;
  }
}

1

해결책은 1) A의 하위 상태가 B의 하위 상태에 가시적인지 여부에 달려 있습니다. 2) AB와 C는 공통 부모로부터 파생됩니다. 공통 부모가 있고 가시성이 보편적이라면 B의 하위 상태에서 A의 하위 상태로 이동하는 데 너무 많은 문제가 없어야합니다.

네임 스페이스 및 / 또는 A, B 및 C를 통해 네임 스페이스를 분리하지 않은 경우 공통 상위가없는 경우 A, B 및 C 머신에 대한 외부 상태 변경 드라이버를 사용하는 것이 가장 좋습니다. 이벤트 핸들러를 통해 수행 할 수 있습니다. B에 발생한 이벤트를 수신하고 이벤트를 기반으로 자체 하위 상태로 전환 할 수있는 A에 관찰자를두기 만하면됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.