ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] 상태(State) 패턴 - 디자인 패턴
    CSE/Design Pattern 2015. 6. 13. 10:50

    Pattern #17  상태 패턴




     객체의 상태에 의하여 결정된 방법으로 객체를 동작하게 할 때 사용




     패턴 요약 

      - 상태 객체를 따로 만들어 포함하게 하고, 상태 객체에게 위임하여 동작하게 함



     

     동기

      

     당신은 새로운 프로젝트의 프로그램 reviewer 책임을 맡았다. Reviewer로 당신은 팀원들이 개발한 핵심 코드를 살펴보고, 논리상의 문제점이나 좋지 않은 설계구조를 지적해 주어야 한다. 오늘 살펴본 코드에는, 특정 객체가 자신의 상태에 따라 다른 행동을 하기 위하여 if 문장을 많이 사용하였다. 그러다 보니, 함수의 크기가 커지고 객체상태가 많은 경우 해당 객체의 구현이 더욱 복잡해졌다. 개발자에게 조언해줄 해결방법은?

     

     







         



    해결방안 

      - 객체의 가능한 상태 개수 만큼 State class를 작성한다.

     



     


      - 일반적으로 State class의 interface는 특정 상태에 따라 객체의 행위가 달라지는 함수들을 포함한다.





      - TCPConnection class와 State Class에 자신의 상태를 변화시킬 수 있는 ChangeState() 메서드를 추가한다.








      - State 객체가 TCPConnection 객체를 알수 있도록 한다.

        * 함수를 호출할 때 인자로 TCPConnection 객체를 넘기던가, 혹은 각 State 객체가 생성될 때 TCPConnection 객체 reference를 가지든가. -> 여기서는 전자로








     - 기존 객체의 상태에 의존적인 함수는 State 객체로의 deleation으로 구현한다.








    - TCPConnection 객체의 상태변화는 내부 함수나 State 객체에서만 일으킬 수 있다(ChangeState()를 private으로)


     



     



    - TCPConnection 객체 상태 변화 예







    - State 객체가 독자적인 정보를 가지지 않는다면, 객체를 여러 개 가질 필요는 없다. 

      * State 객체는 특정 객체의 행위들을 각 상태에 따라 모아 놓은 것이기 때문에 단순 함수 집합으로 간주해도됨.

      * Singleton pattern 활용

      * 앞의 예에서 Singleton pattern을 사용한 모습






    의도 

      - 객체의 내부 상태가 변경되었을 때 그에 따라 객체의 행위도 변경되게 한다.(마치 다른 class의 객체가 된 것 처럼)


    별칭 

      - Objects for States


    적용범위

      - 객체의 행위가 해당 객체의 상태에 따라 달라질 때

      - 객체의 함수 코드가 객체의 상태에 따라 큰 부분의 조건 문장으로 구성되어 있을 때(if 문장, switch 문장)













    예제1.




    State.java

     

    1
    2
    3
    4
    5
    6
    7
     
    package state1;
     
    public interface State {
        public void saySomething(StateContext sc);
    }
     
    cs





    Rich.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    package state1;
     
    public class Rich implements State {
     
        public void saySomething(StateContext sc) {
            System.out.println("I'm rich currently, and play a lot");
            sc.changeState(new Poor());
        }
     
    }
     
    cs





    Poor.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    package state1;
     
    public class Poor implements State {
     
        public void saySomething(StateContext sc) {
            System.out.println("I'm poor currently, and spend much time working");
            sc.changeState(new Rich());
        }
     
    }
     
    cs





    StateContext.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    package state1;
     
    public class StateContext {
        private State currentState;
     
        public StateContext() {
            currentState = new Poor();
        }
     
        public void changeState(State newState) {
            this.currentState = newState;
        }
     
        public void saySomething() {
            this.currentState.saySomething(this);
        }
    }
     
    cs





    StateMain.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    package state1;
     
    public class StateMain {
     
        public static void main(String[] args) {
            StateContext sc = new StateContext();
            
            sc.saySomething();
            sc.saySomething();
            sc.saySomething();
            sc.saySomething();
            
        }
     
    }
     
    cs















    예제2.





    State.java

     

    1
    2
    3
    4
    5
    6
    7
     
    package state2;
     
    public interface State {
        public void doAction();
    }
     
    cs





    TVContext.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    package state2;
     
    public class TVContext implements State {
     
        private State tvState;
     
        public void setState(State state) {
            this.tvState = state;
        }
     
        public State getState() {
            return this.tvState;
        }
     
        public void doAction() {
            this.tvState.doAction();
        }
     
    }
     
    cs





    TVStartState.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    package state2;
     
    public class TVStartState implements State {
     
        public void doAction() {
            System.out.println("TV is turned ON");
        }
     
    }
     
    cs





    TVStopState.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    package state2;
     
    public class TVStopState implements State {
     
        @Override
        public void doAction() {
            System.out.println("TV is turned OFF");
        }
     
    }
     
    cs





    StateMain.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    package state2;
     
    public class StateMain {
     
        public static void main(String[] args) {
            TVContext context = new TVContext();
     
            State tvStartState = new TVStartState();
            State tvStopState = new TVStopState();
     
            context.setState(tvStartState);
            context.doAction();
     
            context.setState(tvStopState);
            context.doAction();
        }
     
    }
     
    cs













    댓글

Designed by Tistory.