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
- 끝 -
'역량 UP! > 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 |