[디자인 패턴] 스테이트(상태) 패턴 (State Pattern)

최진민·2021년 11월 15일
1

디자인 패턴

목록 보기
5/10
post-thumbnail
  • 정의
  • 사용 이유
  • 구현

💊 1. 스테이트 패턴?

  • 스테이트 패턴 (State Pattern)

    • 객체가 상태에 따라 행위를 다르게 할 때, 직접 상태를 체크하여 상태에 따른 행위를 호출하는 것이 아니라 상태를 객체화하여 필요에 따라 다르게 행동하도록 위임하는 디자인 패턴

      • 객체의 특정 상태 = 클래스

      • 상태에 따른 행위 = 클래스 내 메서드

      • 상태 클래스를 인터페이스로 캡슐화

      • 엘리베이터의 예



🪙 2. 사용 이유

  • 엘리베이터 예제를 통해 사용 이유에 대해 설명

  • 엘리베이터는 올라가는 상태(UP), 내려가는 상태(DOWN), 정지 상태(STOP)가 존재

    public class NonElevator {
        public static final String up = "UP";
        public static final String down = "DOWN";
        public static final String stop = "STOP";
        private String curState = "";
    
        public NonElevator() {
            this.curState = stop;
        }
    
        public void setState(String state) {
            this.curState = state;
        }
    
        public void pushUpButton() {
            if (curState.equals(up)) {
                System.out.println("동작 없음");
            } else {
                System.out.println("올라감");
                curState = up;
            }
        }
    
        public void pushDownButton() {
            if (curState.equals(down)) {
                System.out.println("동작 없음");
            } else {
                System.out.println("내려감");
                curState = down;
            }
        }
    
        public void pushStopButton() {
            if (curState.equals(stop)) {
                System.out.println("동작 없음");
            } else {
                System.out.println("멈춤");
                curState = stop;
            }
        }
    }
    • 위와 같은 상황에서 문이 열림, 문이 닫힘과 같이 상태상태에 따른 행위들이 추가될수록 필요한 변수메서드 및 메서드 내부 조건문들이 추가된다.

    • 스테이트 패턴은 상태를 객체화하여 위와 같은 문제를 해결하도록 돕는다.



💡 3. 구현

  • 각 상태 (up, down, stop)을 클래스로 정의한 후, 인터페이스로 묶는다(캡슐화).

  • 엘리베이터는 상태 인터페이스메서드를 호출하여 변경된 행위를 수행한다.

    public interface ElevatorState {
        public void pushUpButton();
        public void pushDownButton();
        public void pushStopButton();
    }
    • 엘리베이터의 상태에서 변화하는 행위들에 대한 메서드를 정의

      public class UpState implements ElevatorState {
          private static UpState upState;
      
          private UpState() {}
      
          public static UpState getInstance() {
              if (upState == null) {
                  upState = new UpState();
              }
              return upState;
          }
      
          @Override
          public void pushUpButton() {
              System.out.println("동작 없음");
          }
      
          @Override
          public void pushDownButton() {
              System.out.println("내려감");
          }
      
          @Override
          public void pushStopButton() {
              System.out.println("멈춤");
          }
      }
      public class DownState implements ElevatorState {
          private static DownState downState;
      
          private DownState() {}
      
          public static DownState getInstance() {
              if (downState == null) {
                  downState = new DownState();
              }
              return downState;
          }
      
          @Override
          public void pushUpButton() {
              System.out.println("올라감");
          }
      
          @Override
          public void pushDownButton() {
              System.out.println("동작 없음");
          }
      
          @Override
          public void pushStopButton() {
              System.out.println("멈춤");
          }
      }
      public class StopState implements ElevatorState {
      
          private static StopState stopState;
      
          private StopState() {}
      
          public static StopState getInstance() {
              if (stopState == null) {
                  stopState = new StopState();
              }
              return stopState;
          }
      
          @Override
          public void pushUpButton() {
              System.out.println("올라감");
          }
      
          @Override
          public void pushDownButton() {
              System.out.println("내려감");
          }
      
          @Override
          public void pushStopButton() {
              System.out.println("동작 없음");
          }
      }
      • 해당하는 상태에서 버튼을 눌렀을 때, 행동이 변화하도록 구현
      • 엘리베이터는 수시로 상태가 변화하기 때문에 싱글톤으로 구현했다. (매번 인스턴스를 생성하지 않아 메모리 낭비를 줄일 수 있도록 구현)
  • 적용된 엘리베이터의 모습 (Context)

    public class AdaptElevator {
      private ElevatorState elevatorState;
    
      public AdaptElevator() {
          this.elevatorState = StopState.getInstance();
      }
    
      public void setElevatorState(ElevatorState state) {
          this.elevatorState = state;
      }
    
      public void pushUpButton() {
          elevatorState.pushUpButton();
          this.setElevatorState(UpState.getInstance());
      }
    
      public void pushDownButton() {
          elevatorState.pushDownButton();
          this.setElevatorState(DownState.getInstance());
      }
    
      public void pushStopButton() {
          elevatorState.pushStopButton();
          this.setElevatorState(StopState.getInstance());
      }
    }
  • 클라이언트의 행동

    public class Client {
        public static void main(String[] args) {
            AdaptElevator elevator = new AdaptElevator();
    
            elevator.pushStopButton();
            elevator.pushDownButton();
            elevator.pushStopButton();
            elevator.pushUpButton();
            elevator.pushStopButton();
            elevator.pushUpButton();
            elevator.pushUpButton();
        }
    }
    
    print >>>
    동작 없음
    내려감
    멈춤
    올라감
    멈춤
    올라감
    동작 없음
  • 그렇다면 Strategy Pattern과 State Pattern의 차이점은 뭘까?

    • Strategy Pattern
      • 상속 대체 (즉, 사용자가 쉽게 알고리즘 전략을 바꿀 수 있도록 유연성을 제공)
    • State Pattern
      • 조건문(if-else, switch 등) 대체 (즉, 한 객체가 동일한 동작을 상태에 따라 다르게 수행해야 할 경우 사용)
    • 또한, 무분별한 스테이트 패턴은 클래스 수의 증가로 인한 단점이 존재
profile
열심히 해보자9999

0개의 댓글