KimMK

상태(State) 패턴 본문

C++/디자인 패턴

상태(State) 패턴

KimMK 2023. 3. 19. 18:04

디자인 패턴 중 행위 패턴인 상태 패턴은 객체 상태를 캡슐화함으로써 참조하게 하는 방식으로 상태에 따라 다르게 처리할 수 있도록 내용을 변경하여, 변경 시 원시 코드의 수정을 최소화할 수 있고, 유지보수의 편의성도 갖는 디자인 패턴이다.

즉, 객체 상태에 따라 동작이 달라지는 경우 사용되는 디자인 패턴으로 객체를 상태(state)와 상태에 따른 동작(action)으로 분리하여 구현하고, 객체의 상태가 변할 때마다 적절한 상태에 맞는 동작을 수행하도록 한다.

 

자기 스스로 상태를 판단해 행동하도록 하는 것인데, 이는 유한 상태 기계(FSM)와 밀접한 관련이 있음

* 유한 상태 기계(FSM): 상태(State)와 상태 전환(Transition)으로 이루어진 모델로, 각 상태에서는 특정 동작을 수행하며 입력이 발생하면 다음 상태로 전환됨

 

FSM은 상태 변화에 따라 시스템의 동작을 제어하는 것이 목적

상태와 전환을 그래프로 나타낼 수 있으며, 이를 상태 전이도(State Transition Diagram)이라고 함

Unreal Engine의 애님그래프

 

쉽게 예를 들어, 자판기를 구현한다고 가정한다.

자판기의 상태는 "돈 투입 대기 상태", "음료 선택 대기 상태", "음료 추출 상태" 등 여러 상태를 가질 수 있는데,

각 상태에 따라 사용자의 동작이 달라지며 자판기의 동작도 달라져야 함

 

이러한 경우 상태 패턴을 사용해 구현할 수 있다. 상태 패턴에서는 자판기를 하나의 객체로 구현하는 대신, 각 상태를 객체로 분리해 구현한다.

그러면 각 상태에 맞는 동작을 쉽게 구현할 수 있으며, 상태 전환에 따른 동작 변경도 쉽게 할 수 있다.

 

간단한 예시

#include <iostream>

using namespace std;

class LightState {
public:
    virtual void switchOn() = 0;
    virtual void switchOff() = 0;
};

class OnState : public LightState {
public:
    void switchOn() {
        cout << "이미 켜져 있습니다." << endl;
    }
    void switchOff() {
        cout << "불을 끕니다." << endl;
    }
};

class OffState : public LightState {
public:
    void switchOn() {
        cout << "불을 켭니다." << endl;
    }
    void switchOff() {
        cout << "이미 꺼져 있습니다." << endl;
    }
};

class Light {
private:
    LightState* state;
public:
    Light() {
        state = new OffState();
    }
    void setState(LightState* state) {
        this->state = state;
    }
    void switchOn() {
        state->switchOn();
    }
    void switchOff() {
        state->switchOff();
    }
};

int main() {
    Light light;

    light.switchOn();  // "불을 켭니다."
    light.switchOff(); // "불을 끕니다."

    light.setState(new OnState());
    light.switchOn();  // "이미 켜져 있습니다."
    light.switchOff(); // "불을 끕니다."

    return 0;
}

 

 

FSM 요점

  • 가질 수 있는 상태가 한정되어 있음(유한한 한정)
  • 한 번에 한 가지의 상태만 될 수 있음
  • 입력이나 이벤트에 따라 상태 전이가 일어나고 이를 반복하며 최종 상태에 도달함
  • 상태와 전이로 구성되므로 적절히 정의해 시스템의 동작을 모델링 할 수 있음 (Enum과 switch~case문으로 구현할 수 있음) 따라서, 간단하고 직관적인 모델링을 가능하게 함

 

FSM을 사용하면 좋을 때

  • 내부 상태에 따라 객체 동작이 바뀔 때
  • 상태 선택지가 많지 않을 때
  • 객체 입력이나 이벤트에 따라 반응할 때

 

문제점

  • 상태 조합이 안 된다. 예를 들어, 점프 중에 공격하기...
  • 상태가 많아지면 매우 복잡해짐(거미줄처럼 여기저기 얽혀 있는 상태들)

유니티 State Machine

  • 입력에 따라 시스템의 상태가 변경되므로 시스템의 복잡도가 증가할수록 입력에 대한 처리가 어려워짐

 

상태 패턴의 요점

  • 상태 패턴은 상태와 상태 전이로 구성된 유한 상태 기계 모델을 사용함
  • 객체의 동작을 변경하는 것이 목적이며, 객체는 내부적으로 상태를 가지고 있음
  • 상태에 따라 객체가 다른 동작을 수행하며, 이를 구현하는 방식으로 상태 클래스를 정의하고 이를 객체에 적용함

 

장점

  1. 코드의 유지 보수성이 향상됨. 새로운 상태가 추가되거나 상태의 동작이 변경되어도 상태 클래스만 수정하면 됨
  2. 객체의 동작이 상태에 따라 변경되므로 코드가 간단하고 가독성이 좋아짐
  3. 코드의 중복을 제거할 수 있음

 

단점

  1. 객체가 다양한 상태를 가지고 있을 때 상태 클래스가 매우 많아질 수 있음
  2. 상태 패턴을 적용하면 클래스의 수가 많아지므로 코드의 복잡도가 증가할 수 있음 → 따라서, 상태의 수와 전이 수를 적절하게 관리하고, 객체 간의 결합도를 줄이기 위해 인터페이스와 추상 클래스를 적극 활용하는 것이 좋음

 

 

'C++ > 디자인 패턴' 카테고리의 다른 글

관찰자(Observer) 패턴  (0) 2023.03.14
싱글턴(Singleton) 패턴  (0) 2023.03.12
경량(Flyweight) 패턴  (1) 2023.03.11
디자인 패턴  (0) 2023.03.11
명령(Command) 패턴  (0) 2023.03.11