[DesignPattern] state pattern

2013. 12. 31. 11:26Architecture/DesignPattern

반응형


2013/12/16 - [Architecture/DesignPattern] - [DesignPattern] memento pattern


2013/12/09 - [Architecture/DesignPattern] - [DesignPattern] mediator pattern


2013/12/03 - [Architecture/DesignPattern] - [DesignPattern] command pattern


2013/11/24 - [Architecture/DesignPattern] - [DesignPattern] observer pattern


2013/11/24 - [Architecture/DesignPattern] - [DesignPattern] Interpreter pattern


2013/07/21 - [Architecture/DesignPattern] - [첫번째 스터디] abstractFactory 패턴


2013/07/21 - [Architecture/DesignPattern] - [첫번째 스터디] singleton 패턴


 

참고 사이트 : http://www.youtube.com/watch?v=MGEx35FjBuo


<< State Design Pattern은 무엇인가?? >>

1) 내부의 상태가 변경되면 객체의 변경을 허용한다. 객체변경이란 무엇인지는 뒤에~

2) 구조

   - Context            : Concrete State의 구현 클래스의 현재 상태의 인스턴스를 유지한다.                              

   - State               : Context의 행동과 연관된 독특한 상태를  interface로  정의한다.

                              한마디로...상태를 나타내는 역할이다.

   - Concrete State : State의 구현부 이다. 즉, 개개의 상태를 표현하는 역할이다.

3) 참고 그림

   

- 참고사이트 : http://en.wikipedia.org/wiki/State_pattern

[클래스 다이어그램] 



소스  : 테스트 소스


package kr.pe.acet.state;

import org.junit.Assert;

import org.junit.Test;


public class StateTest {


@Test

public void test() {

final StateContext sc = new StateContext();

Assert.assertNotNull(sc);


sc.writeName("Monday");

sc.writeName("Tuesday");

sc.writeName("Wednesday");

sc.writeName("Thursday");

sc.writeName("Friday");

sc.writeName("Saturday");

sc.writeName("Sunday");

}


}


소스 : Context  - Concrete State의 구현 클래스의 현재 상태의 인스턴스를 유지한다.


package kr.pe.acet.state;

public class StateContext {

private Statelike myState;


/**

* Standard constructor

*/

StateContext() {

setState(new StateA());

}


/**

* Setter method for the state. Normally only called by classes implementing

* the State interface.

* @param newState

*            the new state of this context

*/

void setState(final Statelike newState) {

myState = newState;

}


/**

* Writer method

* @param name

*            the name to be written

*/

public void writeName(final String name) {

myState.writeName(this, name);

}

}



소스 : State - Context의 행동과 연관된 독특한 상태를  interface로  정의한다.

package kr.pe.acet.state;

public interface Statelike {

 /**

     * Writer method for the state name.

     * @param context the stateful context

     * @param name the name to be written

     */

    void writeName(StateContext context, String name);

 

}



소스 : Concrete State - State의 구현부 이다.


package kr.pe.acet.state;

public class StateA implements Statelike {


@Override

public void writeName(StateContext context, String name) {

       System.out.println(name.toLowerCase());

       context.setState(new StateB());

}


}




package kr.pe.acet.state;

public class StateB implements Statelike {


/** State counter */

private int count = 0;


@Override

public void writeName(final StateContext context, final String name) {

System.out.println(name.toUpperCase());

/* Change state after StateB's writeName() gets invoked twice */

if (++count > 1) {

context.setState(new StateA());

}

}



}



결과

monday

TUESDAY

WEDNESDAY

thursday

FRIDAY

SATURDAY

sunday




음...뭔가 단순하다. 위의 소스에서 그냥 이것저것 해보자.

결과는 이렇게~

[null]에서[kr.pe.acet.state.StateA@1e63e3d]로 변경 되었습니다.

monday

StateA Excute!!

[kr.pe.acet.state.StateA@1e63e3d]에서[kr.pe.acet.state.StateB@1b90b39]로 변경 되었습니다.

오늘은 월요일 입니다.



TUESDAY

StateB Excute!!

오늘은 화요일 입니다.



WEDNESDAY

StateB Excute!!

[kr.pe.acet.state.StateB@1b90b39]에서[kr.pe.acet.state.StateA@18fe7c3]로 변경 되었습니다.

수요일



[kr.pe.acet.state.StateA@18fe7c3]에서[kr.pe.acet.state.StateB@b8df17]로 변경 되었습니다.

THURSDAY

StateB Excute!!

오늘은 목요일 입니다.



FRIDAY

StateB Excute!!

[kr.pe.acet.state.StateB@b8df17]에서[kr.pe.acet.state.StateA@13e8d89]로 변경 되었습니다.

금요일



[kr.pe.acet.state.StateA@13e8d89]에서[kr.pe.acet.state.StateB@1be2d65]로 변경 되었습니다.

SATURDAY

StateB Excute!!

오늘은 토요일 입니다.



SUNDAY

StateB Excute!!

[kr.pe.acet.state.StateB@1be2d65]에서[kr.pe.acet.state.StateA@9664a1]로 변경 되었습니다.

일요일



[kr.pe.acet.state.StateA@9664a1]에서[kr.pe.acet.state.StateB@1a8c4e7]로 변경 되었습니다.

 


TEST Code

package kr.pe.acet.state;

import org.junit.Assert;

import org.junit.Test;


public class StateTest {


@Test

public void statePatternTest() {

final StateContext sc = new StateContext();

Assert.assertNotNull(sc);


sc.writeName("Monday");

sc.getDay("월요일");

sc.writeName("Tuesday");

sc.getDay("화요일");

sc.writeName("Wednesday");

sc.getDay("수요일");

sc.writeName("Thursday");

sc.getDay("목요일");

sc.writeName("Friday");

sc.getDay("금요일");

sc.writeName("Saturday");

sc.getDay("토요일");

sc.writeName("Sunday");

sc.getDay("일요일");

}


}


Context Code

package kr.pe.acet.state;


// 상태를 관리하거나 

public class StateContext {

private State myState;


/**

* Standard constructor

*/

StateContext() {

setState(new StateA());

}


/**

* Setter method for the state. Normally only called by classes implementing

* the State interface.

* @param newState

*            the new state of this context

*/

void setState(final State newState) {

changeState(newState);

myState = newState;

}


/**

* Writer method

* @param name

*            the name to be written

*/

public void writeName(final String name) {

myState.writeName(this, name);

}

// 상태를 하나 추가 

public void getDay(final String name){

myState.changeName(this, name);

}

// 상태 변화 관리

public void changeState(State state){

System.out.println("["+this.myState+"]에서["+state+"]로 변경 되었습니다.");

}

}


State Code

package kr.pe.acet.state;



// 상태를 나타 냄 

public interface State {

 /**

     * Writer method for the state name.

     * @param context the stateful context

     * @param name the name to be written

     */

    void writeName(StateContext context, String name);    

    void changeName(StateContext context, String name); 

 

}


Concrete State Code - StateA 

package kr.pe.acet.state;


public class StateA implements State {


@Override

public void writeName(StateContext context, String name) {

System.out.println(name.toLowerCase());

System.out.println("StateA Excute!!");

context.setState(new StateB());

}


@Override

public void changeName(StateContext context, String name) {

// TODO Auto-generated method stub

System.out.println(name+"\n\n");

context.setState(new StateB());


}


}


Concrete State Code - StateB

package kr.pe.acet.state;


public class StateB implements State {


/** State counter */

private int count = 0;


@Override

public void writeName(final StateContext context, final String name) {

System.out.println(name.toUpperCase());

System.out.println("StateB Excute!!");

/* Change state after StateB's writeName() gets invoked twice */

if (++count > 1) {

context.setState(new StateA());

}

}


@Override

public void changeName(StateContext context, String name) {

System.out.println("오늘은 "+name+" 입니다.\n\n");

}




}


마지막으로 State Pattern의 장단점은??


장점 : 언제 다른 상태로 변하는지 알 수 있는 정보가 하나의 클래스 내에 정리되어 있는 점이다.

즉, 위의 Concrete State Code들을 보면 알 수 있다.


단점 : 하나의 ConcreteState 역할이 다른 ConcreteState 역할을 알아야한다는 점이다. 엥?? 

아까는 장점이라매? 장난치나?? 라고 하실지도 모르겠군요..ㅋㅋ;;

즉, 상태변화를 ConcreteState역할에 맡겨버리면 클래스간의 의존관계를 강하게 만들기 때문에

위의 Class StateA에서 StateB의 객체를 만드는 부분이 있습니다. 이때 StateB가 삭제 되버리면

StateA에도 수정을 가해야하는 단점이 있습니다. 그래서 

Mediator Pattern을 적용 할 수 도 있을 것 같다. 


2013/12/09 - [Architecture/DesignPattern] - [DesignPattern] mediator pattern



- 끝 -










반응형

'Architecture > DesignPattern' 카테고리의 다른 글

[DesignPattern] Iterator pattern  (0) 2014.01.06
[DesignPattern] flyweight pattern  (0) 2014.01.06
[DesignPattern] memento pattern  (0) 2013.12.16
[DesignPattern] mediator pattern  (0) 2013.12.09
[DesignPattern] command pattern  (0) 2013.12.03