상태 패턴(state pattern)은 객체 지향 방식으로 상태 기계를 구현하는 행위 소프트웨어 디자인 패턴이다. 상태 패턴을 이용하면 상태 패턴 인터페이스의 파생 클래스로서 각각의 상태를 구현함으로써, 또 패턴의 슈퍼클래스에 의해 정의되는 메소드를 호출하여 상태 변화를 구현함으로써 상태 기계를 구현한다.
class HeroineState {
public:
virtual ~HeroineState() {}
virtual HeroineState* handleInput(Heroien& heroine, Input input) {}
virtual void update(Heroien& heroine) {}
};
class DuckingState : public HeroineState {
public:
virtual HeroineState* handleInput(Heroien& heroine, Input input) override {
if(input == RELEASE_DOWN)
return new StandingState(); // 다른 파생형 클래스(상태)로 전환
else
return NULL; // 지금 상태를 유지한다.
}
}
class StandingState : public HeroineState {
public :
virtual HeroineState* handleInput(Heroine& heroine, Input input) override {
if(input == PRESS_DOWN)
return new DuckingState(); // 현재 상태(Standing)를 Ducking 상태로 전이
else
return NULL; // 지금 상태를 유지한다.
}
}
상태 인터페이스의 파생형 클래스는 각 상태를 정의하는 클래스다. 이 파생 클래스를 전환해가며
상태 객체 Heroine의 상태를 전환할 수 있다.
class Heroine {
public:
virtual void handleInput(Input input) { state_->handleInput(*this, input); }
virtual void update() { state_->update(*this); }
private:
HeroineState* state_;
};
상태를 바꾸려면 state_에 새로운 상태 객체를 할당해야 한다.
상태가 전이할 때마다 상태 객체를 만들면 FSM이 상태별로 인스턴스를 갖게 된다.
void Heroine::handleInput(Input input) {
HeroineState* state = sate_->handleInput(*this, input); // ※ 새로운 상태의 반환을 시도
if(state != NULL) {
delete state_; // 새로 상태를 할당하기 때문에 이전 상태를 힙에서 해제해야 한다.
state_ = state; // 상태 전환
}
}
Heroine 클래스의 handleInput 메서드가 새로운 상태를 반환하지 않는다면 현재 상태를 삭제하지 않고 유지한다. (return NULL)
이는 잘못된 키 입력이나 키 입력을 하지 않았을 경우 NULL이 반환되어 현재 상태가 유지된다.
서 있기 상태(Standing)에서 엎드리기 상태(Ducking)로 전이하려면 새로운 인스턴스를 생성해(new DuckingState()) 상태를 반환한다.
그 반환된(NULL이 아닌) 상태로 기존 상태 멤버가 전환된다. (state_ = state)
클라이언트에서 인터페이스를 선언하여 상태 패턴을 사용하여 상속된 클래스(상태) 별로 기능을 분리하여 조건문을 대체할 수도 있다.