스테이트(State) 패턴
07 May 2016 | 디자인패턴스테이트(Command) 패턴은 오브젝트의 상태(State)를 클래스화한 패턴입니다.
스테이트 패턴을 사용하지 않았을 경우 만약 각 상태마나 다른 동작을 하게 하기 위해서 if 문을 사용했다면,
public void work() {
  if(현재 상태 == 낮){
    낮에 할 일();
  }
  else if(현재 상태 == 밤){
    밤에 할 일();
  }
}
와 같은 형태의 코드가 됩니다. 각 함수마다 현재 상태에 따라 분기문을 타게 되면, 향후 함수의 개수가 증가할 때마다(또는 상태가 증가할 때마다) 유지 보수가 힘들어지는 경우가 발생할 수 있습니다.
이런 경우 State 패턴을 사용하면 코드를 깔끔하게 관리할 수 있습니다. State 패턴의 UML은 다음과 같습니다.

예제 코드
예제를 살펴 보도록 하겠습니다. 여기서는 아까의 예제와 같이 낮/밤이라는 ‘상태’를 각각 클래스화하도록 할 것입니다. 그리고 낮에는 이미지 갤러리, 밤에는 뮤직 프로그램이 실행되는 프로그램을 생각해보도록 하겠습니다.
일단, 다음과 같은 인터페이스를 만들어보겠습니다.
public interface State {
  public void setTime(ContextManager cm, int hour);
  public void setItem(Item item);
  public void show();
  public void close();
}
그리고, 각 상태는 다음과 같이 구현할 수 있습니다. (여기서는 각 State를 Singleton으로 구현을 했는데, 이 부분은 자유롭게 구현해도 됩니다. 다만 잦은 State 변경에 의해서 State를 재생성해야할 경우가 많다면, State를 매번 생성해야 할 필요가 있는지는 고민해보는 것이 좋을 것 같습니다.)
public class DayState implements State {
  private static DayState mInstance = new DayState();
  private ImageGallery mImageGallery = new ImageGallery();
  private DayState() {
  }
  public static State getInstance() {
    return mInstance;
  }
  @Override
  public void setTime(ContextManager cm, int hour) {
    if((hour < 9) || (hour >= 17)) {
      cm.setState(NightState.getInstance());
    }
    cm.setTime(hour);
  }
  @Override
  public void setItem(Item item) {
    mImageGallery.setItem(item);
  }
  @Override
  public void show() {
    mImageGallery.show();
  }
  @Override
  public void close() {
    mImageGallery.close();
  }
}
public class NightState implements State {
  private static NightState mInstance = new NightState();
  private MusicLibrary mMusicLibrary = new MusicLibrary();
  private NightState() {
  }
  public static State getInstance() {
    return mInstance;
  }
  @Override
  public void setTime(ContextManager cm, int hour) {
    if((hour >= 9) && (hour < 17)) {
      cm.setState(DayState.getInstance());
    }
    cm.setTime(hour);
  }
  @Override
  public void setItem(Item item) {
    mMusicLibrary.setItem(item);
  }
  @Override
  public void show() {
    mMusicLibrary.show();
  }
  @Override
  public void close() {
    mMusicLibrary.close();
  }
}
  