2010-08-15 4 views
9

상태 패턴을 사용하여 C#에서 계층 적 상태 시스템을 구현하려고합니다. 가이드로서 나는 this 예제를 사용하고 있습니다. 이 예제는 계층 적 상태에 대한 대답을 제공하지 않습니다. 불행히도 다른 곳에서는 좋은 예를 찾을 수 없습니다. 내 첫 번째 생각은 계층 적 상태에 대해 중첩 된 클래스를 만드는 것입니다. 그러나 이것이 최선의 방법으로 간주되거나 더 나은 해결책이 있습니까?상태 패턴을 사용하는 계층 적 상태 시스템의 모범 사례는 무엇입니까?

Greets!

UPDATE :

내가 전술 한 바와 같이 주 패턴을 구현하려고 노력 오후 내내 앉아 있었어요. HSM의이 매우 간단한 미디어 플레이어를 기반으로 :

alt text http://www.freeimagehosting.net/uploads/e8d2d6486a.jpg

는 내가 그것을 한 적이 있지만 한 가지 이해가 안 생각했다.

public class MediaPlayer 
{ 
    public MediaPlayerStates state; 

    public MediaPlayer(MediaPlayerStates state) 
    { 
     this.state = state; 
    } 

    public void OnButtonPressed() 
    { 
     state.OnButtonPressed(this); 
    } 

    public void DeviceBooted() 
    { 
     state. ????? 
    } 

    //Other Functions 
} 

//The 3 initial states (Start, On, End) know only 2 events. 
public abstract class MediaPlayerStates 
{ 
    public abstract void OnButtonPressed(MediaPlayer player); 
    public abstract void OffButtonPressed(MediaPlayer player); 
} 

//The very beginpoint of the state machine 
public class Start : MediaPlayerStates 
{ 
    //When hitting the onbutton, the state changes to the OnState state 
    public override void OnButtonPressed(MediaPlayer player) 
    { 
     player.state = new OnState(player); 
    } 

    //No need to implement this one 
    public override void OffButtonPressed(MediaPlayer player) 
    { 
     throw new NotImplementedException(); 
    } 
} 

//OnState implements the 2 events from the MediaPlayerStates abstract class. 
public class OnState : MediaPlayerStates 
{ 
    //When entered the OnState state, a new entrypoint is creaeted: the Start state 
    public OnState(MediaPlayer player) 
    { 
     player.state = new OnStartState(); 
    } 

    //The OnState doesn't have a OnButtonPressed event so it doesn't need to be implemented 
    public override void OnButtonPressed(MediaPlayer player) 
    { 
     throw new NotImplementedException(); 
    } 

    //When hitting the offbutton in the OnState, the new state is End 
    public override void OffButtonPressed(MediaPlayer player) 
    { 
     player.state = new End(); 
    } 

    //The OnState itself containts 3 events, therefore these need to be implemented by every state whitin the OnState state 
    public abstract class SubStates : MediaPlayerStates 
    { 
     public abstract void DeviceBooted(MediaPlayer player); 
     public abstract void PlayButtonPressed(MediaPlayer player); 
     public abstract void StopButtonPressed(MediaPlayer player); 
    } 

    //The OnStartState is the pseudoState where the On state starts 
    public class OnStartState : SubStates 
    { 
     //When booted, the state of the player changes to the ShowMediaFileState state 
     public override void DeviceBooted(MediaPlayer player) 
     { 
      player.state = new ShowMediaFileState(); 
     } 

     //The events below don't need to be implemented since they don't exist. 
     public override void PlayButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void StopButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void OnButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void OffButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    public class ShowMediaFileState : SubStates 
    { 
     //This event doesn't exists for this state 
     public override void DeviceBooted(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     //When hitting the play button in this state, play the mediafile 
     public override void PlayButtonPressed(MediaPlayer player) 
     { 
      player.state = new PlayMediaFileState(); 
     } 

     //These events also don't exist for this state 
     public override void StopButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void OnButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void OffButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    public class PlayMediaFileState : SubStates 
    { 
     //This event doesn't exist for this state 
     public override void DeviceBooted(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     //This event doesn't exist for this state 
     public override void PlayButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     //While playing a file and hitting the stopbutton, the state changes to the ShowMediaFileState state 
     public override void StopButtonPressed(MediaPlayer player) 
     { 
      player.state = new ShowMediaFileState(); 
     } 

     //This event doesn't exist for this state 
     public override void OnButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 

     //This event doesn't exist for this state 
     public override void OffButtonPressed(MediaPlayer player) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

//The endstate doesn't need any implementation since there cannot occur a event while being off 
public class End : MediaPlayerStates 
{ 
    public override void OnButtonPressed(MediaPlayer player) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void OffButtonPressed(MediaPlayer player) 
    { 
     throw new NotImplementedException(); 
    } 
} 

MediaPlayer를 클래스에서 이벤트를 정의 할 때, 나는 다른 기능을 호출 할 수 없습니다 다음

  • 을 OnButtonPressed : 우선 내가 작성한 코드는 (죄송합니다, 꽤 알이 많이있다)

그래서 궁금을 OffButtonPressed, 내 구현은 어떤 좋은? 뭐가 잘못 되었 니? 또한 복합 패턴을 사용하라는 제안을 보려고했지만 상태 패턴과 함께 사용해야하는 방법을 이해하지 못했습니다. 아무도 도울 수 있기를 바랍니다!

+0

당신이 IEnumerable을 고려 얻을 수 있나요 :

여기 자매 자바 스크립트 버전의 프로젝트 사이트로 살펴보고, 작업 예제를 보려면? 언어 내에서 직접적인 간단한 상태 기계 메커니즘을 제공합니다. 예. http://www.yoda.arachsys.com/csharp/csharp2/iterators.html (그물에있는 많은 예제들 중 하나) – Will

+0

귀하의 제안을 볼 수있는 한 좋은 아이디어는 아닙니다. 내가 개념에 익숙하지 않아서 나는 그것을 찾았고 이것을 발견했다 : http://stackoverflow.com/questions/1194853/implementing-a-state-machine-using-the-yield-keyword 그럼에도 불구하고 나는 당신의 의견을 고맙게 여기고있다. :) – user341877

답변

3

여러분은 Composite도 원할 것입니다. 그러면 상태 머신을 함께 연결할 수 있습니다.

1

자신 만의 FSM 프레임 워크를 구현하기 전에 SMC - State Machine Compiler를 살펴보십시오.

SMC는 상태 시스템의 텍스트 정의를 취하여이를 구현하는 코드를 생성합니다. C#을 비롯한 다양한 언어의 백엔드가 있습니다. 또한 도트 파일을 출력하여 FSM의 다이어그램을 생성 할 수 있습니다.

SMC는 푸시 및 팝 전환을 사용하여 계층 적 상태 시스템과 비슷한 것을 만들 수 있습니다. 기본적으로 푸시 전환을 새 상태 시스템으로 전환하고 팝은 원래 상태 시스템으로 제어를 반환합니다.

+0

FSM을 생성 할 수있는 프레임 워크가 얼마나 훌륭한 지, 나는 오히려 내 자신의 FSM을 만들려고합니다. Besided, 나는 프로젝트에서 많은 프레임 워크 파일을 갖고 싶지 않습니다. 나는 단순하고 깨끗한 FSM을 만들고 싶습니다. – user341877

2

상태 패턴을 사용하여 HSM을 작성하려면 하위 상태가있는 각 상태가 상태 시스템 자체 여야합니다. 이 방법으로 상위 레벨은 하위 상태에 대한 지식이 없으므로 하위 상태를 더 잘 관리 할 수 ​​있습니다 (기본 상태를 가질 수 있고 마지막 상태를 기억할 수 있음).

행동에 유용한 어떤 것도 할 수 없을 때 예외를 throw하는 것은 잘못되었습니다. 그냥 무시해야합니다. 예외적 인 경우에만 예외를 던지며 잘못된 버튼을 누르면 예상되는 사용자 동작입니다.

+0

+1 : "... 잘못된 버튼을 누르면 예상되는 사용자 행동입니다." 이것은 아주 정상입니다. 예외적 인 경우는 거의 없습니다 - 프로그래머가 이것을 이해하고 싶습니다! – quamrana

1

일반적인 방식으로 작동 시키려면 상태 시스템의 계층 구조를 트리 구조로 처리해야합니다. 노드 간의 전이는 트리에 대해 최소 공통 조상 (LCA) 알고리즘을 사용하고 소스 노드 조상 (모든 자식 노드로 종료를 계단식으로 연결)에서 공통 조상 아래의 노드에서 종료 한 다음 대상 노드 조상의 각 노드를 노드를 대상 노드에 연결하고 마지막으로 대상 노드에 자식이있는 경우 다른 복합 상태를 입력하는 것처럼 입력해야합니다.

이것은 UML 상부 구조 사양에서 언급 한 방법입니다.

https://github.com/steelbreeze/state.cs의 소스 코드를 살펴보면 위의 방법대로 구현됩니다. http://www.steelbreeze.net/state.js/

관련 문제