2013-11-22 11 views
0

나는 현재 리팩토링있어 게임 내 나는 그것의 읽기 및 시각적 정의 형식 선택 this example 기반으로하는 유한 상태 기계,에 AI :이 상태 머신 클래스는 부모 객체에 의해 인스턴스화Finite State Machine을 사용하여 포함 된 객체를 제어하기위한 OO 접근 방식은 무엇입니까?

class FiniteStateMachine 
{ 
    public enum States { Start, Standby, On }; 
    public States State { get; set; } 

    public enum Events { PlugIn, TurnOn, TurnOff, RemovePower }; 

    private Action[,] fsm; 

    public FiniteStateMachine() 
    { 
     this.fsm = new Action[3, 4] { 
     PlugIn,  TurnOn,     TurnOff,   RemovePower 
     {this.PowerOn, null,     null,    null},    //start 
     {null,   this.StandbyWhenOff, null,    this.PowerOff},  //standby 
     {null,   null,     this.StandbyWhenOn, this.PowerOff} }; //on 
    } 
    public void ProcessEvent(Events theEvent) 
    { 
     this.fsm[(int)this.State, (int)theEvent].Invoke(); 
    } 

    private void PowerOn() { this.State = States.Standby; } 
    private void PowerOff() { this.State = States.Start; } 
    private void StandbyWhenOn() { this.State = States.Standby; } 
    private void StandbyWhenOff() { this.State = States.On; } 
} 

이 간단한 예제와 일치 시키려면 "Device"이라고 부릅니다.

내가 지금 고민하고있는 것은 다양한 상태 및 전환 동작을 구현하기 위해이 기능을 확장하는 것이 가장 좋은 방법입니다. Device 클래스에는 카운터가 있으며, 전원을 켤 때마다 증가시키고 싶다고 가정 해 보겠습니다. 카운터를 어떻게 늘릴 수 있습니까?

여기에서 전환 동작에 사용 된 Action 대리자는 FiniteStateMachine 클래스 외부에서 매개 변수를 가져 오지 않습니다. 어쨌든 여기에서 포함 된 클래스를 변경하는 것은 끔찍한 습관 일 것입니다.

그러나이 클래스에서 실제 동작을 구현하지 않을 경우, 우선 Finite State Machine을 구현할 시점을 놓친 것처럼 느껴집니다. 불법적 인 상태 변경을 시도 할 때 Null 참조 예외를 던지는 이점을 이해하지만 계획은 동작도 포함해야합니다.

그렇다면 실제로 어떤 기존 동작 코드도 변경하지 않고 있습니다. 호출 코드에서 State을 직접 설정하는 대신 ProcessEvent()을 호출하기 위해 리 팩터링합니다. 더 안전하지만 청소기가 아닙니다.

그래서 제 질문은 다음과 같습니다
1. 클래스를 포함하는 것에 영향을 미치는 유한 상태 기계의 행동 요소를 구현하는 가장 깨끗한 방법이 있을까요?
2. 위의 FSM 모델을 버려야이를 수행 할 수 있습니까?

+1

[국가] (http://en.wikipedia.org/wiki/State_pattern) 디자인 패턴 확인 – zerkms

답변

0

state pattern (zerkms의 의견에서 제안하는대로)을 확인해야합니다.

이렇게하면 상태 전환에 대한 추가 작업을 쉽게 구현할 수 있습니다.

상태 패턴을 사용할 때 개별 상태에서 데이터를 공유하는 방법을 결정해야합니다. 컨텍스트 클래스에 공유 데이터를 넣으면 공개하지 않고 상태에 공개하는 것은 어렵습니다. C++ 구현은 종종 friend을 사용하여 상태가 컨텍스트에서 개인 데이터에 액세스 할 수 있도록합니다. C#에서는 때로는 컨텍스트에서 상태로 전달되지만 컨텍스트 또는 상태에 의해 공개적으로 노출되지 않는 별도의 클래스에 공유 데이터를 캡슐화했습니다.

일단 상태 패턴을 알아 내고 나면 그 점이 분명하지 않은 경우 댓글을 추가하면 코드를 게시 할 수 있습니다.

+0

나는 주 디자인 패턴을 살펴 봤는데 지금은 이해하고 있다고 생각합니다. 필자가 본 구현 사례는 예상보다 약간 복잡하지만 그 이유는 알 수 있습니다. 상태 디자인 패턴은 "PowerOff"또는 모든 'nulls'와 같은 중복 된 전환 방법을 허용하지 않는 것 같습니다. 이 문제를 해결하기위한 방법이 있습니까? 아니면 각 구체적인 상태 클래스에서 코드를 복제해야합니까? – Quasar

+0

상태 클래스간에 상속을 사용할 수 있습니다. 일반적으로 각 이벤트에 대한 기본 동작을 갖는 기본 상태 클래스를 가질 수 있으며 자식 클래스에서 필요에 따라 재정의 할 수 있습니다. 예제에서 null은 FSM이 특정 상황에서 이벤트를 처리 할 수 ​​없다는 것을 의미합니다 (실제로 시도하면 throw됩니다). 상태 패턴을 사용할 때 이벤트에 대한 기본 응답은 종종 동일한 상태로 유지됩니다. – Ergwun