2. 자판기의 동작 방식
동작(이벤트) 조건 실행 결과
동전을 넣는다 동전 없음이면 금액을 추가 제품 선택 가능
동전을 넣는다 제품 선택 가능이면 금액을 증가 제품 선택 가능
제품 선택하면 동전 없음이면 아무 동작 동전 없음 유지
하지 않음
제품 선택하면 제품 선택 가능이면 제품 주고 잒액 있으면 제품 선택 가능
잒액 감소 잒액 없으면 동전 없음
3. 조건 문을 이용한 구현
class VendingMachine {
final int NOCOIN = 1;
final int SELECTABLE = 2;
insertCoin(int coin) {
if (state == NOCOIN) {
increaseCoin(coin);
세척 중인 경우와
state = SELECTABLE;
} else if (state == SELECTABLE) { 품절인 경우도
increaseCoint(coin);
처리해야 한다…
}
}
select(int productId) {
if (state == NOCOIN) {
doNothing();
} else if (state == SELECTABLE) {
provideProduct(productId);
decreaseCoin();
if (isNoCoin()) {
state = NOCOIN;
}
}
}
4. 새로운 조건 추가
class VendingMachine {
final int NOCOIN = 1;
final int SELECTABLE = 2;
final int CLEANING = 3;
if-else 때문에
final int SOLDOUT = 4;
코드가 복잡해 질 것 같은
불길한 냄새가 남
insertCoin(int coin) {
if (state == NOCOIN) {
increaseCoin(coin);
state = SELECTABLE;
} else if (state == SELECTABLE) {
increaseCoint(coin);
} else if (state == CLEANING) {
returnCoin();
} else if (state == SOLDOUT) {
returnCoin();
}
}
…
}
5. 처리 방식을 한번 더 생각해보면
class VendingMachine {
final int NOCOIN = 1;
final int SELECTABLE = 2;
final int CLEANING = 3;
final int SOLDOUT = 4;
상태에 따라
insertCoin(int coin) {
동일한 요청의 상태에 의존하는
if (state == NOCOIN) {
처리가 바뀜 조건절이 많음
increaseCoin(coin);
state = SELECTABLE;
} else if (state == SELECTABLE) {
increaseCoint(coin);
} else if (state == CLEANING) {
returnCoin();
} else if (state == SOLDOUT) {
returnCoin();
}
}
…
}
8. Context
• 클라이언트가 필요한 기능(인터페이스) 제공
• 내부적으로 State에 요청 처리 위임
class VendingMachine {
VendingMachine private State state;
-state : State
public void insertCoin(int coin) {
+insertCoin(coin : int) state.insertCoint(coin, this);
}
+selectProduct(productId : int)
+chageState(state : State) public void selectProduct(int productId) {
state.selectProduct(productId, this);
}
public void changeState(sState newState) {
this.state = newState;
}
}
9. State & Concrete State
• State
– 모든 상태에 공통된 기능 처리를 정의
• Concrete State - 특정 상태의 기능 처리를 구현
class NoCoinState implements State {
public void insertCoin(int coin,
VendingMachine machine) {
// 동전 증가
machine.changeState(selectableState);
}
public void selectProduct(
int productId,
VendingMachine machine) {
beep();
}
}
10. 패턴 적용 후, 조건 문 → 여러 State
class VendingMachine {
final int NOCOIN = 1;
NoCoinState
final int SELECTABLE = 2;
final int CLEANING = 3;
final int SOLDOUT = 4;
insertCoin(int coin) {
SelectableState
if (state == NOCOIN) {
increaseCoin(coin);
state = SELECTABLE;
} else if (state == SELECTABLE) {
increaseCoint(coin);
CleaingState
} else if (state == CLEANING) {
returnCoin();
} else if (state == SOLDOUT) {
returnCoin();
}
SoldOutState
}
…
}
11. 구현 이슈 1 - State의 전이는 누가
• 안1, State에서 상태 전이 처리
class ConcreteState implements State {
public void behavior1(int coin, Context context) {
// do something
context.changeState(nextState);
}
}
– State 구현 클래스 갂 커플링 발생
NoCoinState SelectableState
CleaningState
• 안2, Context에서 상태 전이 처리
– Context의 코드가 다소 복잡해짐
12. 구현 이슈 2 - 테이블 기반 구현
• 상태 전이를 표로 표현
현재 상태 입력 값 다음 상태
A 1 B
A 2 C
C 1 Z
• State 패턴과의 차이점
– 테이블 기반 구현 - 상태의 전이에 초점
– State 패턴 구현 - 상태에 특화된 기능 제공에 초점
13. State 패턴 정리
• 상태에 특정한 기능의 처리 구현을 여러 클래스
에 분산
– 새로운 상태 추가 용이
• 새로운 State 구현 클래스 추가로 상태 추가 가능
– 긴 조건문을 피할 수 있음
– 클래스가 많아짐
• 상태 전이가 명시적
– 상태 관련 코드가 구조화 됨
– 코드의 구조나 의도를 명확하게 함