객체의 내부 상태가 변경될 때 해당 객체가 ctx의 행동을 변경할 수 있도록 하는 패턴
객체가 행동을 변경할 때 객체가 클래스를 변경한 것처럼 보일 수 있다.
궁금증은 아래서
상태 패턴은 객체의 내부상태 변화에 따라 객체의 동작을 변경할 수 있는 패턴
이 패턴은 유한 상태 기계의 개념과 유사
상태 패턴은 패턴 인터페이스에 정의된 메서드 호출을 통해 전략을 전환할 수 있는 전략 패턴으로 해석 가능
정해진 상태들 사이를 규칙에 따라 이동하는 기계(하드웨어)
신호등(초록, 노랑, 빨강), 자판기(돈 -> 음료선택(유한)), 개찰구(open-close) 등 ->
상태 패턴은 FSM이라는 이론적 개념을 소프트웨어에서 OOP로 구현한 패턴

class Document is
field state: string
// …
method publish() is
switch (state)
"draft":
state = "moderation"
break
"moderation":
if (currentUser.role == "admin")
state = "published"
break
"published":
// Do nothing.
break
// …
아아.. 이런 코드는 OOP에서 OCP원칙을 위반한다고~ 쓰지말라고!
아래서 한번 절차지향적/객체지향적 장단점에 대해 얘기해봄
조건문들에 기반한 상태 머신의 가장 큰 약점은 상태들과 상태에 의존하는 행동들을 추가할수록 분명해지겠죠?
조금 더 구체적으로는?
3. context(ctx)라는 원래 객체는 모든 행동을 구현하는 대신 "현재 상태"를 나타내는 상태 객체 중 하나에 대한 참조를 저장 + 모든 상태와 관련된 작업을 해당 클래스에 위임
ㅇㅎ 상태를 만들겠군 State합성 합성 영어로는 ? 콤포지숀(Composition)~~~
그리고 State는 합성이니깐 고수준 모듈(interface)이겠고 이거슬 구현한 ConcreteState가 있겠군!

Context = 리모컨
State<<interface>> = 현재 TV 상태 인터페이스
ConcreteState = 실제 상태들

일단은 간단하게 켜기/끄기만 구현
interface TVState {
pressButton(tv: TV): void;
}
// TV off 상태
class TVOffState implements TVState {
pressButton(tv: TV): void {
console.log('티비가 켜짐!');
tv.setState(new TVOnState());
}
}
class TVOnState implements TVState {
pressButton(tv: TV): void {
console.log('티비가 꺼짐!');
tv.setState(new TVOffState());
}
}
class TV {
private state: TVState = new TVOffState();
setState(state: TVState) {
this.state = state;
}
public pressPower() {
this.state.pressButton(this);
// this를 호출한 객체.
}
}
// -------CLIENT-------
const tv = new TV();
tv.pressPower(); // off -> on
tv.pressPower(); // on -> off
여기서 음량 조절 채널 버튼을 추가하면 어떻게 될까?
상태패턴은 유한한 상태지만 많은 상태가 있어야 유의미한거잖아요!
interface TVState {
pressButton(tv: TV): void;
// 음량, 채널
pressChannel(direction: 'up'| 'down'): void
pressVolume(direction: 'up'|'down'): void
// 그외 음소거 버튼 등등등 ..
}

전략 패턴과 비슷해 보이지만 한 가지 중요한 차이점이 있습니다. 상태 패턴에서의 특정 상태들은 서로를 인식하고, 한 상태에서 다른 상태로 천이(on -> off)를 시작할 수 있지만 전략패턴들은 대부분 서로에 대해 알지 못한다는 것입니다.
전략 패턴은 사용자가 필요에따라 런타임에 바꿔!! 바꿔!! 바꿔!! 가능 (사용자가 갑)
상태 패턴은 사용자가 X "응~ 니가 누르는거에 따라서 알아서 바뀔거야~" (상황이 갑)
솔직히 잘 모르겠음..
const tv = new TV(); // TV 객체는 하나
tv.pressPower(); // "티비가 켜짐!" → ON 상태의 행동
tv.pressPower(); // "티비가 꺼짐!" → OFF 상태의 행동
상태 패턴을 사용하면 다음과 같은상태를 가진 클래스로 바꾼것처럼 행동한다는 뜻
실제로는 변경없음, 상태만 변경됨
tv.state = new TVOnState()
tv.state = new TVOffState()
근데 꼭 절차지향이 나쁜건 아니거덩요.
언어라는 도구를 잘 활용하면 좋거덩요
꼭 oop에 갇혀 있을 필욘 없거덩요
상황에 맞춰서 쓰면 되거덩요
그러하거덩요
#include <stdio.h>
// 상태 ENUM
typedef enum {
TV_OFF,
TV_ON
} TVState;
// 데이터 구조체 (행동 없음, 데이터만)
typedef struct {
TVState state;
} TV;
// 함수가 구조체 밖에 존재
void press_power(TV* tv) {
switch (tv->state) {
case TV_OFF:
printf("티비가 켜짐!\n");
tv->state = TV_ON;
break;
case TV_ON:
printf("티비가 꺼짐!\n");
tv->state = TV_OFF;
break;
}
}
int main() {
TV tv = { TV_OFF }; // 초기화
press_power(&tv); // 포인터로 넘김
press_power(&tv);
return 0;
}
또한 상태가 많지 않다면 가독성 + 유지보수성은 절차지향이 편리함 (등가교환)
"뭐가 더 자주 바뀌냐" 에 따라 선택이 달라짐
기능(함수)이 자주 추가 -> 절차지향
타입(클래스)이 자주 추가 -> OOP
절차지향은 자료구조는 바꾸기 어렵지만 함수 추가는 EZPZ
OOP는 자료구조는 바꾸기 쉽지만 함수 추가는 HARD