728x90
반응형
기획 요구사항에 따라 '정지', '재생', '일시정지' 등 객체의 상태가 늘어날 때마다 if (state == STOP) 같은 조건문이 계속 늘어나고 있지는 않나요? 상태가 많아질수록 코드는 읽기 힘들어지고 유지보수는 불가능에 가까워집니다.
오늘은 객체의 상태를 클래스로 캡슐화하여, 상태에 따라 행동을 스스로 바꾸게 만드는 상태 패턴(State Pattern)에 대해 알아보겠습니다.

1. 상태 패턴이란?
상태 패턴은 객체의 내부 상태가 바뀜에 따라 객체의 행동을 변경할 수 있게 해주는 패턴입니다. 객체는 마치 클래스를 바꾸는 것과 같은 결과를 얻을 수 있습니다.
왜 상태 패턴인가?
- 조건문 제거: 상태 제어 로직이 각 상태 클래스로 분산되어 거대한 switch 문이 사라집니다.
- 단일 책임 원칙(SRP): 각 상태와 관련된 행동은 해당 클래스에만 집중됩니다.
- 상태 전이의 명확함: 상태가 언제, 어떻게 바뀌는지 로직이 투명하게 드러납니다.
2. 상태 패턴 vs 전략 패턴 (차이점)
구조적으로는 두 패턴이 거의 동일하지만, 의도(Intention)에서 큰 차이가 있습니다.
| 구분 | 전략 패턴 (Strategy) | 상태 패턴 (State) |
| 목적 | 알고리즘이나 로직의 교체 | 상태에 따른 행동 변화 및 전이 관리 |
| 상호작용 | 클라이언트가 어떤 전략을 쓸지 결정함 | 상태 클래스들이 스스로 다음 상태를 결정하기도 함 |
| 관점 | "어떤 방법으로 수행할 것인가?" | "지금 어떤 상태인가?" |
3. Java 실무 예제: 문서 승인 워크플로우
단순한 출력을 넘어, 문서의 승인 여부에 따라 자동으로 다음 상태로 전이되는 구조를 구현해 보겠습니다.
Step 1. State 인터페이스 정의
Java
interface DocumentState {
void edit(Document doc);
void approve(Document doc);
}
Step 2. 구체적인 상태 클래스 (Concrete States)
Java
// 초안 상태
class DraftState implements DocumentState {
@Override
public void edit(Document doc) {
System.out.println("📝 문서를 수정합니다.");
}
@Override
public void approve(Document doc) {
System.out.println("✅ 검토 단계로 보냅니다.");
doc.setState(new ReviewState()); // 상태 전이
}
}
// 검토 중 상태
class ReviewState implements DocumentState {
@Override
public void edit(Document doc) {
System.out.println("❌ 검토 중에는 수정할 수 없습니다.");
}
@Override
public void approve(Document doc) {
System.out.println("🎉 최종 승인되었습니다!");
doc.setState(new PublishedState()); // 상태 전이
}
}
// 출판 완료 상태 (PublishedState는 생략)
Step 3. Context 클래스 (Document)
Java
class Document {
private DocumentState state;
public Document() {
this.state = new DraftState(); // 초기 상태
}
public void setState(DocumentState state) {
this.state = state;
}
public void edit() { state.edit(this); }
public void approve() { state.approve(this); }
}
4. 상태 패턴의 장단점
👍 장점
- 유지보수성: 새로운 상태가 추가되어도 기존 Context나 다른 상태 클래스를 수정할 필요가 없습니다. (OCP 준수)
- 직관성: 상태별 로직이 한곳에 모여 있어 코드 가독성이 비약적으로 상승합니다.
👎 단점
- 클래스 개수 증가: 상태가 많아질수록 관리해야 할 클래스 파일이 늘어납니다.
- 복잡도: 상태 전이가 단순한 경우 오히려 오버헤드가 될 수 있습니다.
5. 실제 사용 사례
- TCP 연결 상태: (LISTEN, ESTABLISHED, CLOSED) 상태에 따른 패킷 처리.
- 자동판매기: (동전 없음, 동전 있음, 상품 선택 중) 상태 관리.
- 게임 캐릭터: (아이들링, 달리기, 점프, 공격) 상태에 따른 애니메이션 및 조작 변경.
결론
상태 패턴은 단순히 조건문을 없애는 기술이 아니라, 복잡한 상태 전이를 객체 지향적으로 설계하는 철학입니다. 객체의 행동이 내부 상태에 강하게 의존하고 있다면, 지금 바로 상태 패턴 도입을 고민해 보세요!
도움이 되셨다면 공감과 구독 부탁드립니다!
여러분은 프로젝트에서 어떤 복잡한 상태를 관리하고 계신가요? 댓글로 공유해 주세요!
반응형
'Mobile & App Stack > Java Software Architecture & Patterns' 카테고리의 다른 글
| 이터레이터 패턴: 데이터 구조와 상관없이 일관되게 순회하는 법 (0) | 2025.01.06 |
|---|---|
| 비지터 패턴(Visitor): 기존 코드 수정 없이 기능을 무한 확장하는 법 (0) | 2025.01.05 |
| 템플릿 메서드 패턴: 중복 코드를 줄이는 상속의 기술 (Java 예제) (0) | 2025.01.03 |
| 커맨드 패턴 완벽 정리: Undo/Redo 기능을 만드는 가장 스마트한 방법 (0) | 2025.01.02 |
| 옵저버 패턴(Observer) 완벽 정리: Java 예제와 Deprecated 대안 (0) | 2025.01.01 |