상태패턴이란?
객체의 내부 상태가 변경될 때 동작을 전환하도록 하는 디자인 패턴이다.
상태별 동작을 개별 클래스로 분리해 조건문 if-else, switch 복잡도를 제거하는게 핵심 목적이다
왜 if-else를 분리할까?
간단한 조건문은 if-else를 나누면 되지만 조건에 따라 동작하는게 복잡해지고, 또 확작을 계속 하고 싶을 때 유지보수가 힘들어지기 때문이다.
상태패턴 구성 요소
- Context
- 상태를 관리하는 주체
- State Interface
- 모든 상태의 공통 인터페이스 정의
- Concrete State
- 구체적인 상태별 동작 구현
- Context가 State 인터페이스에 작업 위임
- Concrete State 객체에서 실제 동작 수행
- 상태 변경 시 Context의 상태 포인터 갱신
장단점
장점
- 조건문 감소: 상태 검증 로직 제거 → 코드 가독성 향상
- 확장성: 새 상태 추가시 기존 코드 수정 불필요(OCP 준수)
- 책임 분리: 각 상태의 동작이 독립적 클래스에 캡슐화
단점
- 과도한 클래스 생성: 단순 상태 머신에는 부적합
- 상호 의존성: Context ↔ State 양방향 참조 시 복잡도 증가
예시
상태 인터페이스
class Lamp; // 전방 선언
class LampState
{
public:
virtual void toggle(Lamp* lamp) = 0;
virtual ~LampState() = default;
};
구체적인 상태 클래스( Concrete State )
// 켜진 상태
class OnState : public LampState
{
public:
void toggle(Lamp* lamp) override;
};
// 꺼진 상태
class OffState : public LampState
{
public:
void toggle(Lamp* lamp) override;
};
// 깜빡이는 상태
class BlinkState : public LampState
{
public:
void toggle(Lamp* lamp) override;
};
Context클래스
class Lamp
{
private:
LampState* currentState;
public:
Lamp() : currentState(new OffState()) {}
void setState(LampState* newState)
{
delete currentState;
currentState = newState;
}
void toggle()
{
currentState->toggle(this);
}
~Lamp()
{
delete currentState;
}
};
// 상태별 동작 구현
void OnState::toggle(Lamp* lamp)
{
std::cout << "램프 꺼짐" << std::endl;
lamp->setState(new OffState());
}
void OffState::toggle(Lamp* lamp)
{
std::cout << "램프 켜짐" << std::endl;
lamp->setState(new OnState());
}
void BlinkState::toggle(Lamp* lamp)
{
std::cout << "램프 깜빡임 중지" << std::endl;
lamp->setState(new OffState());
}
이렇게 펼쳐서 보면 이해가 쉽다. 그래서 전에 배운 전략패턴과 뭐가 다를까?
전략패턴과의 비교
기준 | 상태 패턴 | 전략패턴 |
역할 | 상태 변화에 따른 동작 변경 | 알고리즘 교체 |
변경 주체 | 상태 객체 자체 | 외부에서 주입 |
상호 영향 | 다른 상태로 전이 가능 | 전략 독립적 실행 |
이렇게 된다.
게임에서 사용할 때
드래곤 퀘스트에서의 공격같은 경우 전략패턴으로 만들면 좋고
이동 애니메이션 등은 상태패턴으로 만들면 좋겠다! 라는 생각이 든다. 행동패턴들은 유사해서 헷갈릴 수 있으니 제대로 기억하도록 하자
'C++ > 개념정리' 카테고리의 다른 글
빌더 패턴 (0) | 2025.03.11 |
---|---|
템플릿 메서드 패턴 (2) | 2025.03.07 |
전략패턴 (0) | 2025.02.26 |
[디버그 입문] (1) | 2025.02.11 |
개념정리[연산자(&*)] (0) | 2025.02.07 |