mojo's Blog
State Pattern 본문
State Pattern
목적: 객체 상황을 객체의 동작과 연결하여 객체가 내부 상태에 따라 다른 방식으로 동작할 수 있도록 함
사용 시기
- 객체의 행동은 객체의 상태에 의해 영향을 받아야 함
- 복잡한 조건은 객체 동작을 상태와 연결함
- 상태 간 전환은 명시적이여야 함
위와 같은 상태 다이어그램을 코딩해보자
public class Eraser {
final static int IDLE = 0;
final static int AWAITING_INPUT = 1;
final static int IN_PROGRESS = 2;
final static int COMPLETE = 3;
int state;
public Eraser() {
state = AWAITING_INPUT;
}
public void begin() {
if (state == IDLE) {
state = IN_PROGRESS;
System.out.println("Idle => In Progress");
}
else if (state == AWAITING_INPUT)
System.out.println("Waited status");
else if (state == IN_PROGRESS)
System.out.println("Progressed status");
else if (state == COMPLETE)
System.out.println("Completed status");
}
public void reset() { // impl reset }
...
}
작업을 수행하는 메서드마다 if 문을 4개의 상태 별로 구현이 이뤄져야 한다.
코드의 가독성이 떨어지는 문제가 발생한다.
※ New Design (composition)
- Eraser의 모든 작업에 대한 메서드를 포함하는 상태 인터페이스를 정의함
- 시스템의 모든 상태에 대해 상태 클래스를 구현함
- 머신이 해당 상태에 있을 때 머신의 동작을 담당함
- 위와 같이 조건부 코드를 모두 제거하고 대신 작업을 수행하도록 주 객체에게 위임함
public class Eraser {
State idleState;
State awaitingInputState;
State inProgressState;
State completeState;
State state;
public Eraser() {
idleState = new IdleState(this);
awaitingState = new AwaitingState(this);
inProgressState = new InProgressState(this);
completeState = new CompleteState(this);
state = awaitingInputState;
}
public void begin() {
state.begin();
}
public void reset() {
state.reset();
}
...
}
public class IdleState implements State {
Eraser eraser;
public IdleState(Eraser eraser) {
this.eraser = eraser;
}
public void begin() {
eraser.setState(eraser.getInProgressState());
System.out.println("Idle => In Progress");
}
public void reset() {
System.out.println("Don't reset (Idle status)");
}
public void input() {
System.out.println("Don't input (Idle status)");
}
public void calculation() {
System.out.println("Don't calculation (Idle status)");
}
public void solution() {
System.out.println("Don't solution (Idle status)");
}
}
원래 버전과 구조적으로 다르지만, 기능적으로는 동일하다.
변경 사항
- 각 상태의 동작을 고유 클래스로 현지화함
- 유지 관리가 어려울 것으로 예상되는 번거로운 조건문을 모두 제거
- 수정을 위해 각 상태를 닫았지만, 새 상태 클래스를 추가하여 Eraser을 확장할 수 있도록 열어둠
- 상태 다이어그램에 훨씬 더 가깝고 매핑되고 읽기 쉽고 이해하기 쉬운 코드 베이스 및 클래스 구조를 만듬
※ The State Pattern
상태 패턴을 사용하면 객체의 내부 상태가 변경될 때 객체의 동작을 변경할 수 있다.
객체가 클래스를 변경하는 것으로 나타난다.
객체의 동작은 객체의 상태에 따라 다르며, 객체는 해당 상태에 따라 런타임에 동작을 변경해야 한다.
연산에는 객체의 상태에 따라 큰 다중 부분 조건문이 존재한다.
상태 패턴은 조건의 각 분기를 별도의 클래스에 배치함으로써 조건문을 없앤다.
※ State v.s. Strategy
State
- 상태 종속 동작을 캡슐화함
- 시간이 지남에 따라 컨텍스트의 동작이 바뀜
Strategy
- 알고리즘을 캡슐화함
- 종종 컨텍스트 객체에 가장 적합한 전략 객체가 있음
- 하위 분류에 대한 유연한 대안
두 패턴 전부 delegation을 활용한 composition 이다.
'Design Patterns' 카테고리의 다른 글
Factory Method Pattern & Abstract Factory Pattern (0) | 2024.06.09 |
---|---|
Mediator Pattern (0) | 2024.06.06 |
Template Method Pattern (0) | 2024.06.06 |
Observer Pattern (1) | 2024.06.06 |
Strategy Pattern (0) | 2024.06.06 |