내부 상태를 바꿈으로써 객체에서 행동을 바꾸는 것을 도와준다.

GumballMachine.java
public class GumballMachine {
final static int SOLD_OUT = 0;
final static int NO_QUARTER = 1;
final static int HAS_QUARTER = 2;
final static int SOLD = 3;
int state = SOLD_OUT;
int count = 0;
public GumballMachine(int count) {
this.count = count;
if (count > 0) {
state = NO_QUARTER;
}
}
public void insertQuarter() {
if (state == HAS_QUARTER) {
System.out.println("동전은 한 개만 넣어주세요");
} else if (state == NO_QUARTER) {
System.out.println("동전을 넣으셨습니다.");
state = HAS_QUARTER;
} else if (state == SOLD_OUT) {
System.out.println("매진되었습니다. 다음에 이용해주세요.");
} else if (state == SOLD) {
System.out.println("잠깐만 기다려 주세요. 알맹이가 나가고 있습니다.");
}
}
/**
* 동전 반환
*/
public void ejectQuarter() {
if (state == HAS_QUARTER) {
System.out.println("동전이 반환됩니다.");
state = NO_QUARTER;
} else if (state == NO_QUARTER) {
System.out.println("동전을 넣어주세요.");
} else if (state == SOLD) {
System.out.println("이미 알맹이를 뽑으셨습니다.");
} else if (state == SOLD_OUT) {
System.out.println("동전을 넣지 않으셨습니다. 동전이 반환되지 않습니다.");
}
}
public void turnCrank() {
if (state == SOLD) {
System.out.println("손잡이는 한 번만 돌려주세요.");
} else if (state == NO_QUARTER) {
System.out.println("동전을 넣어주세요.");
} else if (state == SOLD_OUT) {
System.out.println("매진되었습니다.");
} else if (state == HAS_QUARTER) {
System.out.println("손잡이를 돌리셨습니다.");
state = SOLD;
dispense();
}
}
private void dispense() {
if (state == SOLD) {
System.out.println("알맹이가 나가고 있습니다.");
count -= 1;
if (count == 0) {
System.out.println("더 이상 알맹이가 없습니다.");
state = SOLD_OUT;
} else {
state = NO_QUARTER;
}
} else if (state == NO_QUARTER) {
System.out.println("동전을 넣어주세요.");
} else if (state == SOLD_OUT) {
System.out.println("매진입니다.");
} else if (state == HAS_QUARTER) {
System.out.println("알맹이가 나갈 수 없습니다.");
}
}
public String toString() {
String stateStr = null;
if (state == SOLD_OUT)
stateStr = "알맹이 매진";
else if (state == NO_QUARTER)
stateStr = "동전없음(투입 대기중)";
else if (state == HAS_QUARTER)
stateStr = "동전있음";
else if (state == SOLD) {
stateStr = "알맹이판매";
}
return "남은 개수: "+ count + "\n기계상태: " + stateStr;
}
}
GumballMachineTest.java
import org.junit.Test;
public class GumballMachineTest {
@Test
public void 테스트() {
GumballMachine gumballMachine = new GumballMachine(5);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.ejectQuarter();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}
GumballMachine.java
public class GumballMachine {
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State state = soldOutState;
int count = 0;
public GumballMachine(int numberGumballs) {
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
this.count = numberGumballs;
if (numberGumballs > 0) {
state = noQuarterState;
}
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
state.dispense();
}
public void setState(State state) {
this.state = state;
}
public void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count -= 1;
}
}
public void refill(int count) {
this.count = count;
state = noQuarterState;
}
public State getSoldOutState() {
return soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public State getSoldState() {
return soldState;
}
public State getState() {
return state;
}
public int getCount() {
return count;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("\nMighty Gumball, Inc.");
sb.append("\nJava-enabled Standing Gumball Model #2004");
sb.append("\nInventory: " + count + " gumball");
if (count != 1) {
sb.append("s");
}
sb.append("\nMachine is " + state + "\n");
return sb.toString();
}
}
State.java
public interface State {
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispense();
}
SoldOutState.java
public class SoldOutState implements State {
private GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("동전을 넣을 수 없습니다. 매진입니다.");
}
public void ejectQuarter() {
System.out.println("알맹이를 꺼낼 수 없습니다.");
}
public void turnCrank() {
System.out.println("손잡이를 돌리셨습니다. 알맹이가 매진되었습니다.");
}
public void dispense() {
System.out.println("알맹이가 매진되었습니다.");
}
public String toString() {
return "알맹이 매진";
}
}
NoQuarterState.java
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("동전을 넣으셨습니다.");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
public void ejectQuarter() {
System.out.println("동전을 넣어주세요.");
}
public void turnCrank() {
System.out.println("동전을 넣어주세요.");
}
public void dispense() {
System.out.println("동전을 넣어주세요.");
}
public String toString() {
return "동전없음";
}
}
HasQuarterState.java
public class HasQuarterState implements State {
private GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("동전은 한 개만 넣어주세요.");
}
public void ejectQuarter() {
System.out.println("동전이 반환됩니다.");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
public void turnCrank() {
System.out.println("손잡이를 돌리셨습니다.");
gumballMachine.setState(gumballMachine.getSoldState());
}
public void dispense() {
System.out.println("알맹이가 나갈 수 없습니다.");
}
public String toString() {
return "동전있음";
}
}
SoldState.java
package net.dblab.hfdp.state.after;
public class SoldState implements State {
private GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("잠깐만 기다려주세요. 알맹이가 나가고 있습니다.");
}
public void ejectQuarter() {
System.out.println("이미 알맹이를 뽑으셨습니다.");
}
public void turnCrank() {
System.out.println("손잡이는 한 번만 돌려주세요.");
}
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops!! out of gumballs!!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
public String toString() {
return "알맹이 나가는 중";
}
}
객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.

(상속이 아닌) Composition을 통해 행동을 정의하는 객체를 만든다.
