스테이트(State) 패턴

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

스테이트패턴

뽑기 기계의 상태 변화

상태변화

객체의 상태에 따라서 실행되는 행위가 달라져야 할 때
→ 객체 내부에서 if 절 또는 switch - case 절 의 전개

// 동전을 투입하는 행위
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 interface State {

  void insertQuarter();

  void ejectQuarter();

  void turnCrank();

  void dispense();
}

각 상태들을 구현한다면
→ 해당 상태의 코드만 적용하면 됨

public class SoldState implements State {
  GumballMachine gumballMachine;

  public SoldState(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.releaseBall();
    if (gumballMachine.getCount() > 0) {
      gumballMachine.setState(gumballMachine.getNoQuarterState());
    } else {
      System.out.println("매진입니다.");
      gumballMachine.setState(gumballMachine.getSoldOutState());
    }
  }
}

아래 코드로 GumballMachine 객체 내부의 상태 객체를 변화 시킴

gumballMachine.setState(gumballMachine.getNoQuarterState());

GumballMachine을 사용하는 클라이언트 입장에서는 객체의 클래스가 바뀌는 것 처럼 느낄 수 있음

GameballMachine의 메서드를 State인터페이스가 왜 대부분 가져가는가?

스테이트 패턴은 _내부 상태에 따라서 변화되는 행위를 추상화하는 것_이므로,
상태에 따라 변화되는 행위들을 모두 담아야 한다.

다이어그램은 스트래티지패턴과 동일한 것 같은데?

스트래티지는 구성을 이용하여 상속을 대체하는 것이라면,
스테이트는 수많은 조건문의 대체하는 것이라고 보면 됨