해당 포스트는 "자바 객체지향 디자인 패턴", "JAVA 언어로 배우는 디자인 패턴 입문" 책의 내용을 요약한 것이다.



※상태(State) 패턴

상태에 따라 동일한 작업이 다른 방식으로 실행될 때 해당 상태가 작업을 수행하도록 위임하는 디자인 패턴으로 각각의 상태 별로 클래스를 만들고 해당 클래스 안에 액션/이벤트 메서드를 구현한다. 해당 패턴은 무분별한 if/else if 문으로 OOP를 해칠 때 쓰는 패턴.

 

 

ex) 형광등 클래스

public class Light {
   private static int ON = 0; //형광등이 켜진 상태
   private static int OFF = 1; //형광등이 꺼진 상태
   private int state;  //형광등의 현재 상태

   public Light(){
          state = OFF;  //형광등의 초기 상태는 꺼져 있는 상태
   }
   public void on_button_pushed(){
        if(state == ON){
              System.out.println("반응 없음");
        }   // 형광등이 꺼져 있을 때 On 버튼을 누를 시
        else{
              System.out.println("Light on");
              state = ON;
         }
    }
     public void off_button_pushed(){
          if(state == OFF){
                System.out.println("반응 없음");
           }
           else{   //형광등이 켜져 있을 때 Off 버튼을 누를 시
                 System.out.println("Light off");
                 state = OFF;
            }
     }
}

 

- 문제점

형광등에 새로운 상태를 추가할 때, 가령 '취침등' 상태를 추가해 형광등이 켜져 있을 때 On을 누르면 '취침등' 상태로 변경되고 '취침등' 상태에 있을 때 On을 누르면 형광등이 다시 켜지고 Off 버튼을 누르면 꺼지게 된다. 이런 요구사항이 추가된다면 코드에서 on_button_pushed() 와 off_button_pushed() 메서드를 수정해야 한다. 또한 복잡한 조건문이 현재 시스템의 상태 변화를 파악하는 데 용이하지도 않다. 

 

 

- 해결책 

무엇이 변하는가를 찾고 변하는 부분을 캡슐화 해야한다. 위 예에서는 상태가 계속 변화하고 Light 클래스가 상태에 의존적이기 때문에 상태를 클래스로 분리해 캡슐화해야 한다. 아래는 스테이트 패턴으로 구현한 형광등 클래스 다이어그램이다.

 

 

Light 클래스에서 구체적인 상태 클래스가 아닌 추상화된 State 인터페이스만 참조하므로 현재 어떤 상태에 있는지와 무관하게 코드를 작성할 수 있다. Light 클래스에서는 단지 상태 클래스에 작업을 위임만 하면 된다.

 

interface State {
   public void on_button_pushed(Light light);
   public void off_button_pushed(Light light);
}
public class ON implements State{
   public void on_button_pushed(Light light){
            System.out.println("반응 없음");
   }
   public void off_button_pushed(Light light){
          System.out.println("Light Off");
          light.setState(new OFF(light));
   }
}
public class Light{
     private State state;
     
     public Light(){
           state = new OFF();
     }
     public void setState(State state){
           this.state = state;
      }
     public void on_button_pushed(){
           state.on_button_pushed(this);
      }
      public void off_button_pushed(){
           state.off_button_pushed(this);
      }
}

Light 클래스의 코드를 보면 구체적인 상태를 나타내는 객체를 참조하지 않는다. 즉, Light 클래스는 시스템이 어떤 상태에 있는지와 무관하다는 의미다. 따라서 상태가 새로운 상태로 교체되더라도 Light 클래스는 전혀 영향을 받지 않는다. 그러나 위 코드는 개선할 점이 있다. 상태 변화가 생길 때마다 새로운 상태 객체를 생성하므로 메모리 낭비와 성능 저하를 가져올 수 있기 때문이다. 그래서 상태 객체는 한 번만 생성해도 충분하므로 싱글턴 패턴으로 구현해주면 좋다.

 

public class OFF implements State{
   private static OFF off = new OFF();
   private OFF() {}
   public static OFF getInstance(){
         return off;
   }
   public void on_button_pushed(Light light){
            System.out.println("Light on");
            light.setState(ON.getInstance());
   }
   public void off_button_pushed(Light light){
          System.out.println("반응 없음");
   }
}


'자바 > 디자인패턴' 카테고리의 다른 글

중재자(Mediator) 패턴  (0) 2017.07.04
커맨드(Command) 패턴  (0) 2017.07.03
싱글턴(Singleton) 패턴  (0) 2017.07.03
스트래티지(Strategy, 전략) 패턴  (0) 2017.07.01
디자인 패턴  (0) 2017.06.29

+ Recent posts