상태 state 패턴 - 타입스크립트 예시
요약
상태 state 패턴을 타입스크립트 코드와 함께 알아봅니다.
상태 (State) 패턴 요약
패턴 종류 | 핵심 키워드 |
---|---|
상태 (State) | 객체의 내부 상태가 변경될 때, 객체의 행동 방식도 함께 변경, 상태 변경, 행동 변경 |

상태 (State) 패턴
상태 패턴은 객체의 내부 상태가 변경될 때, 객체의 행동 방식도 함께 변경되도록 하는 패턴입니다. 이 패턴을 사용하면, 객체는 마치 자신의 클래스가 바뀌는 것처럼 보입니다. if/else
나 switch
문으로 가득 찬 상태 관리 코드를, 상태를 나타내는 각각의 클래스로 분리하여 훨씬 깔끔하게 만들 수 있습니다.
'신호등' 을 생각하면 쉽습니다. 신호등은 '초록불', '주황불', '빨간불'이라는 상태를 가집니다. 각 상태일 때 신호등의 행동(다음 상태로 변경되는 것)은 완전히 다릅니다. 초록불일 때는 주황불로, 주황불일 때는 빨간불로, 빨간불일 때는 초록불로 바뀝니다. 상태 패턴은 이처럼 상태에 따른 행동들을 별도의 클래스로 캡슐화하고, 상태가 변할 때 행동을 책임질 클래스 자체를 교체해버리는 방식입니다.
기본 구조
- Context: 상태를 가지는 주체입니다. 현재 상태를 나타내는
State
객체에 대한 참조를 가집니다. 클라이언트의 요청을 받으면, 현재State
객체에게 행동을 위임합니다. 또한, 상태 객체가Context
의 상태를 변경할 수 있도록setState()
와 같은 메서드를 제공합니다. - State: 모든 구체적인 상태 클래스들이 구현해야 할 공통 인터페이스입니다.
Context
가 위임할 행동들을 메서드로 정의합니다. (예:handle()
) - ConcreteState:
State
인터페이스를 구현하는 구체적인 클래스입니다. 특정 상태일 때의 행동을 구현하며, 필요에 따라Context
의 다음 상태를 결정하고 변경합니다.
예시: 온라인 문서의 게시 워크플로우
'초안(Draft)' -> '검토 중(Moderation)' -> '게시됨(Published)' 상태를 가지는 온라인 문서 객체를 만들어 보겠습니다.
먼저, 모든 상태가 따라야 할 DocumentState
인터페이스를 정의합니다.
// State 인터페이스
interface DocumentState {
publish(): void;
}
다음으로, 상태를 가질 Context
객체인 Document
클래스를 만듭니다.
// Context: 상태를 가지는 문서 객체
class Document {
private state: DocumentState;
constructor() {
// 초기 상태는 '초안'
this.state = new DraftState(this);
}
// 상태 변경을 위한 메서드
changeState(state: DocumentState): void {
this.state = state;
}
// 현재 상태에 행동을 위임
publish(): void {
this.state.publish();
}
}
이제 각 상태에 대한 행동을 정의하는 ConcreteState
클래스들을 만듭니다.
// ConcreteState 1: 초안 상태
class DraftState implements DocumentState {
constructor(private document: Document) {}
publish(): void {
console.log("[초안] -> [검토 중]으로 상태를 변경합니다.");
this.document.changeState(new ModerationState(this.document));
}
}
// ConcreteState 2: 검토 중 상태
class ModerationState implements DocumentState {
constructor(private document: Document) {}
publish(): void {
console.log(
"[검토 중] -> [게시됨]으로 상태를 변경합니다. 이제 글이 공개됩니다!"
);
this.document.changeState(new PublishedState(this.document));
}
}
// ConcreteState 3: 게시됨 상태
class PublishedState implements DocumentState {
constructor(private document: Document) {}
publish(): void {
console.log("[게시됨] 이미 게시된 상태입니다. 아무것도 하지 않습니다.");
// 상태 변경 없음
}
}
클라이언트 코드는 Document
객체의 publish()
메서드만 호출하면 됩니다.
// 클라이언트 코드
const myDocument = new Document();
console.log("--- 1. 초안 상태에서 게시 시도 ---");
myDocument.publish(); // 초안 -> 검토 중
console.log("\n--- 2. 검토 중 상태에서 게시 시도 ---");
myDocument.publish(); // 검토 중 -> 게시됨
console.log("\n--- 3. 게시된 상태에서 게시 시도 ---");
myDocument.publish(); // 아무 일도 일어나지 않음
Document
클래스 안에는 if (state === 'draft') { ... } else if (state === 'moderation') { ... }
와 같은 조건문이 전혀 없습니다. 모든 상태 관련 로직은 각각의 State
클래스에 위임되었습니다. 만약 '반려됨(Rejected)'이라는 새로운 상태가 필요하다면, RejectedState
클래스를 만들어 추가하기만 하면 되므로 '개방-폐쇄 원칙(OCP)'을 잘 따릅니다.
상태 패턴 중요 키워드
- 상태에 따른 행동을 별도의 클래스로 캡슐화합니다.
- 객체가 내부 상태에 따라 행동을 바꾸도록 합니다. (마치 클래스가 바뀌는 것처럼)
- 복잡한
if/else
또는switch
문으로 된 상태 머신 코드를 정리하는 데 매우 효과적입니다.- 상태 전환의 책임이
Context
가 아닌 개별State
클래스에 있어 규칙이 명확해집니다.
문제 | 객체의 내부 상태가 변경될 때 객체의 행동 방식도 함께 변경되도록 하는 패턴으로, 상태에 따른 행동을 별도의 클래스로 캡슐화하여 복잡한 if/else나 switch 문으로 된 상태 머신 코드를 정리하는 데 매우 효과적인 디자인 패턴은? |
보기 | |
답변 | |
정답 | 정답 보기 |