티스토리 뷰
StatePattern : 객체 내부 상태가 변경되었을 때 행동 패턴을 바꿀 수 있도록 해준다.
StatePattern을 구현하는 방법에는 여러가지가 있다.
1. State-driven transition
2. Context-driven transition
3. Singleton, State-driven transition
4. Singleton, Context-driven transition
5. + 열거형을 통한 방법 (context-driven, state-driven)
1. State-driven transition
2. Context-driven transition
이 두 방식을 구현해보자면, 아래와 같다.
main
Door door = new Door(); door.close(); door.lock(); door.open(); door.unlock(); door.open();
1. State-driven transition을 알아보면, Context 클래스에 각 상태를 나타내는 멤버를 가지고 있으며, 각 상태에게 Context를 전달하고 각 상태 클래스에서 Context의 changeState와 같은 메소드를 이용하여 상태를 전이한다.
Door
public class Door { private final DoorState openState = new Opened(this); private final DoorState closedState = new Closed(this); private final DoorState lockedState = new Locked(this); private DoorState currentState = closedState; public void open() { currentState.open(); } public void close() { currentState.close(); } public void lock() { currentState.lock(); } public void unlock() { currentState.unlock(); } public void changeToOpenedState() { currentState = openState; } public void changeToClosedState() { currentState = closedState; } public void changeToLockedState() { currentState = lockedState; } }
문의 상태를 정의하는 인터페이스
public interface DoorState { void open(); void close(); void lock(); void unlock(); }
DoorState를 상속받아 정의하는 클래스들(Locked, Opened, Closed)
public class Locked implements DoorState { private Door door; public Locked(Door door) { this.door = door; } @Override public void open() { System.out.println("문이 잠겨있어 열 수 없음"); } @Override public void close() { System.out.println("문이 이미 닫혀있음"); } @Override public void lock() { System.out.println("문이 이미 잠겨있음"); } @Override public void unlock() { System.out.println("문의 잠금을 해제함"); door.changeToClosedState(); } }
public class Opened implements DoorState { private Door door; public Opened(Door door) { this.door = door; } @Override public void open() { System.out.println("이미 열려 있음"); } @Override public void close() { System.out.println("문이 닫힘"); door.changeToClosedState(); } @Override public void lock() { System.out.println("열려있는 상태에서는 잠글 수 없음"); } @Override public void unlock() { System.out.println("문이 열려있어 잠금을 해제할 필요가 없음"); } }
public class Closed implements DoorState { private Door door; public Closed(Door door) { this.door = door; } @Override public void open() { System.out.println("문이 열림"); door.changeToOpenedState(); } @Override public void close() { System.out.println("문이 이미 닫혀있음"); } @Override public void lock() { System.out.println("문이 잠김"); door.changeToLockedState(); } @Override public void unlock() { System.out.println("문이 잠겨 있지 않아 해제할 필요가 없음"); } }
2. Context-driven transition을 알아보면, 각 상태 클래스가 context 외에 별도 멤버를 유지할 필요가 없고, 상태 전이가 고정되어 있으면 상태전이를 context에서 할 수 있다.
Door의 형태가 조금 바뀐다.
public class Door { private final DoorState openState = new Opened(); private final DoorState closedState = new Closed(); private final DoorState lockedState = new Locked(); private DoorState currentState = closedState; public void open() { if(currentState.open()) currentState = openState; } public void close() { if(currentState.close()) currentState = closedState; } public void lock() { if(currentState.lock()) currentState = lockedState; } public void unlock() { if(currentState.unlock()) currentState = closedState; } }
DoorState의 함수들의 반환값을 boolean으로 변경해야한다. ( 조건에 따른 일처리를 위해 )
Locked, Opened, Closed클래스도 boolean타입에 맞도록 변경해준다. 변경되야하는 상태이면 true, 아니면 false를 반환한다.
public class Locked implements DoorState { @Override public boolean open() { System.out.println("문이 잠겨있어 열 수 없음"); return false; } @Override public boolean close() { System.out.println("문이 이미 닫혀있음"); return false; } @Override public boolean lock() { System.out.println("문이 이미 잠겨있음"); return false; } @Override public boolean unlock() { System.out.println("문의 잠금을 해제함"); return true; } }
State-driven transition방식보다 상대적으로 조건문을 사용하게 된다.
전략 패턴과 비교
전략 패턴은 한 메소드의 전략을 동적으로 바꾸는 것이며, 외부에서 이를 원할 때 바꾼다.
상태 패턴은 한 메소드의 전략으로 제한되지 않으며, 스스로 상태 전이가 이루어진다. (전략 패턴에 비해 수시로 바뀜)
'Paradigm > OOP' 카테고리의 다른 글
[OOP] SRP 확인하기 (0) | 2013.09.27 |
---|---|
[OOP] MVC패턴익히기 (0) | 2013.06.06 |
[OOP] TemplatePattern (0) | 2013.05.13 |
[OOP] AdapterPattern (0) | 2013.05.10 |
[OOP] 초기화를 위한 Null Object (0) | 2013.04.27 |
- Total
- Today
- Yesterday