객체의 내부상태가 변경됨에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
시나리오
뽑기 기계의 상태
뽑기 기계를 가정했을때 뽑기 기계의 상태를 다음과 같이 정리해 볼 수 있다.
- 알맹이 매진상태
- 동전있음
- 동전없음
- 알맨이 판매
기계의 코드에 상태코드를 두어 각 행위(insertCoin(), ejectQuartar(), turnCrank()…등)에서 각각의 상태코드를 체크하게되면 복잡한 if문이 구성되면서 행위 분리 원칙에도 위배된다.
다음과 같은코드가 행위를 제어하는 메소드 마드 들어가게 된다.
public void insertQuarter() {
if (state == HAS_QUARTER) {
System.out.println("You can't insert~~~");
} else if (state == NO_QUARTER) {
state = HAS_QUARTER;
System.out.println("You inserted a quarter~~");
} else if (state == SOLD_OUT) {
System.out.println("You can't insert a quarter,~~~");
} else if (state == SOLD) {
System.out.println("Please wait, we're already~~");
}
}
à 대안책으로
상태객체들을 별도의 코드로 구성하고 어떠한 행동일 일어나면 현재상태의 객체에서 필요한 작업을 처리하게 하는 것이다.
다음은 각각의 상태를 모델링하고 State 인터페이스와 NoQuartarState 에 대한 코드이다.
package headfirst.state.gumballstate;
public interface State {
public void insertQuarter(); public void ejectQuarter(); public void turnCrank(); public void dispense(); }
|
package headfirst.state.gumballstate;
public class NoQuarterState implements State { GumballMachine gumballMachine;
/** * 생성자를 통해서 뽑기기계에대한 레퍼런스가 전달된다. * @param gumballMachine */ public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; }
/* NoQuarter 상태에서 동전을 넣게되면 이미 동전이 있다는 메시지를 출력하고 * 뽑기 기계의레퍼런스를 다른 객체의 상태로 바꿈으로써 다음 상태로 전환된다. * @see headfirst.state.gumballstate.State#insertQuarter() */ public void insertQuarter() { System.out.println("You inserted a quarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); }
public void ejectQuarter() { System.out.println("You haven't inserted a quarter"); }
public void turnCrank() { System.out.println("You turned, but there's no quarter"); }
public void dispense() { System.out.println("You need to pay first"); }
public String toString() { return "waiting for quarter"; } }
|
상태의 전환은 State클래스에 의해 제어할 수도 있고, Context클래스에 의해서 제어할 수도 있다.
객체의 내부상태가 변경됨에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있으며 Context 객체(GumballMachine)는 해당 상태에대한 행동의 책임을 해당 상태클래스에게 위임한다.
다음은 상태제어 테스트 클래스이다.
package headfirst.state.gumballstate;
public class GumballMachineTestDrive {
public static void main(String[] args) { // 뽑기 알맹이의 개수를 초기화 한다. GumballMachine gumballMachine = new GumballMachine(5);
System.out.println(gumballMachine);
gumballMachine.insertQuarter(); gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter(); gumballMachine.turnCrank(); gumballMachine.insertQuarter(); gumballMachine.turnCrank();
System.out.println(gumballMachine); } }
|
실행결과
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 5 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 4 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 2 gumballs
Machine is waiting for quarter
소스코드 파일
GumballMachine.javaGumballMachineTestDrive.javaHasQuarterState.javaNoQuarterState.javaSoldOutState.javaSoldState.javaState.java
'Java Design Pattern' 카테고리의 다른 글
디자인패턴의 분류 (0) | 2013.02.22 |
---|---|
Iterator 패턴 & Composite 패턴 (0) | 2013.02.21 |
Template Method 패턴 (0) | 2013.02.20 |
Factory 패턴 (0) | 2013.02.20 |
Decorator 패턴 (0) | 2013.02.20 |