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) {
state = HAS_QUARTER;
System.out.println("동전을 넣으셨습니다.");
} else if(state == SOLD_OUT) {
System.out.println("매진되었습니다. 다음 기회에 이용해 주세요");
}else if(state == SOLD) {
System.out.println("알맹이를 내보내고 있습니다.");
}
}
public void ejectQuarter() {
if(state == HAS_QUARTER) {
state = NO_QUARTER;
System.out.println("동전이 반환 됩니다");
} else if(state == NO_QUARTER) {
System.out.println("동전을 넣어주세요");
} else if(state == SOLD_OUT) {
System.out.println("이미 알맹이를 뽑으셨습니다");
}else if(state == SOLD) {
System.out.println("동전을 넣지 않으셨습니다 동전이 반환되지 않습니다");
}
}
public void turnCrank() {
if(state == HAS_QUARTER) {
state = SOLD;
System.out.println("손잡이를 돌리셨습니다");
} else if(state == NO_QUARTER) {
System.out.println("동전을 넣어주세요");
} else if(state == SOLD_OUT) {
System.out.println("매진되었습니다. 다음 기회에 이용해 주세요");
}else if(state == SOLD) {
System.out.println("손잡이는 한번만 돌려주세요");
}
}
public void dispense() {
if(state == HAS_QUARTER) {
System.out.println("알맹이를 내보낼수 없습니다");
} else if(state == NO_QUARTER) {
System.out.println("동전을 넣어주세요");
} else if(state == SOLD_OUT) {
System.out.println("매진되었습니다. 다음 기회에 이용해 주세요");
}else if(state == SOLD) {
System.out.println("알맹이를 내보내고 있습니다.");
count = count -1;
if(count == 0) {
System.out.println("더이상 알맹이가 없습니다");
state = SOLD_OUT;
}else {
state = NO_QUARTER;
}
}
}
}
다음과 같이 뽑기 기계 코드가 있을때
기능을 추가하기 위해서는 모든 메서드에 추가해야한다.

class GumballMachine {
State soldOutState;
State noQuarterState;
State hasQuarState;
State soldState;
State state = soldOutState;
int count = 0;
public GumballMachine(int numberGumballs) {
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarState = new HasQuarterState(this);
soldState = new SoldState(this);
this.count = numberGumballs;
if(numberGumballs > 0) {
state = noQuarterState;
}else {
state = soldOutState;
}
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
}
public void dispense() {
state.dispense();
}
void releasBall() {
System.out.println("알맹이를 내보내고 있습니다.");
if(count > 0 ) {
count = count -1;
}
}
public State getSoldOutState() {
return soldOutState;
}
public void setSoldOutState(State soldOutState) {
this.soldOutState = soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public void setNoQuarterState(State noQuarterState) {
this.noQuarterState = noQuarterState;
}
public State getHasQuarState() {
return hasQuarState;
}
public void setHasQuarState(State hasQuarState) {
this.hasQuarState = hasQuarState;
}
public State getSoldState() {
return soldState;
}
public void setSoldState(State soldState) {
this.soldState = soldState;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public class HasQuarterState implements State {
GumballMachine gumballMachine;
@Override
public void insertQuarter() {
System.out.println("동전은 한개만 넣어주세요");
}
@Override
public void ejectQuarter() {
System.out.println("동전이 반환됩니다");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("손잡이를 돌리셨습니다");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("알맹이를 내보낼수 없습니다");
}
}
public class NoQuarterState implements State{
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("동전을 넣었습니다");
gumballMachine.setState(gumballMachine.getHasQuarState());
}
@Override
public void ejectQuarter() {
System.out.println("동전을 넣어주세요");
}
@Override
public void turnCrank() {
System.out.println("동전을 넣어주세요");
}
@Override
public void dispense() {
System.out.println("동전을 넣어주세요");
}
}
public class SoldOutState implements State{
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("죄송합니다 매진되었습니다.");
}
@Override
public void ejectQuarter() {
System.out.println("동전을 반환할수 없습니다 ㄷ오전을 넣지 않았습니다");
}
@Override
public void turnCrank() {
System.out.println("죄송합니다 매진되었습니다");
}
@Override
public void dispense() {
System.out.println("알맹이를 내보낼수 없습니다.");
}
}
public class SoldState implements State{
GumballMachine gumballMachine;
@Override
public void insertQuarter() {
System.out.println("알맹이를 내보내고 있습니다.");
}
@Override
public void ejectQuarter() {
System.out.println("알맹이를 뽑으셨습니다");
}
@Override
public void turnCrank() {
System.out.println("손잡이는 한번만 돌려주세요");
}
@Override
public void dispense() {
gumballMachine.releasBall();
if(gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else {
System.out.println("Oops, out of gumballs");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}



상태패턴을 사용하면 객체의 내부 상태가 바꾸미에 따라 객체의 행동을 바꿀수 있습니다. 마치 객체 클래스가 바뀌는 것과 같은 결과를 얻을수 있습니다.

상태패턴을 사용할때는 상태에 일련된 행동이 캡슐화 됨
클라이언트는 상태객체를 몰라도 됨
전략패턴을 사용할때 클라이언트가 context 객체에게 어떤 전략 객체를 사용할지 지정
전략패턴은 서브클래스를 만드는 방법을 대신해서 유연성 극대화 하는 용도
conext 객체 수많은 조건문을 넣는 대신 상태 패턴을 사용한다 생각하면 됨
public class WinnerState implements State {
GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("알맹이를 내보내고 있습니다.");
}
@Override
public void ejectQuarter() {
System.out.println("알맹이를 뽑으셨습니다");
}
@Override
public void turnCrank() {
System.out.println("손잡이는 한번만 돌려주세요");
}
@Override
public void dispense() {
gumballMachine.releasBall();
if(gumballMachine.getCount() == 0) {
gumballMachine.setState(gumballMachine.getSoldOutState());
}else {
gumballMachine.releasBall();
System.out.println("축하드립니다 알맹이를 하나 더 받으실수 있습니다.");
if(gumballMachine.getCount() >0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("더이상 알맹이가 없습니다.");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
}
public class HasQuarterState implements State {
GumballMachine gumballMachine;
Random randomWinner = new Random(System.currentTimeMillis());
@Override
public void insertQuarter() {
System.out.println("동전은 한개만 넣어주세요");
}
@Override
public void ejectQuarter() {
System.out.println("동전이 반환됩니다");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("손잡이를 돌리셨습니다");
int winner = randomWinner.nextInt(10);
if((winner == 10) && (gumballMachine.getCount() > 1)) {
gumballMachine.setState(gumballMachine.getWinnerState());
}else {
gumballMachine.setSoldOutState(gumballMachine.getSoldState());
}
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("알맹이를 내보낼수 없습니다");
}
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
}