티스토리 뷰

Paradigm/OOP

[OOP] StatePattern

Mr.SIM 2013. 5. 28. 02:32

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