상태머신
객체 상태 다이어그램
상태 머신 다이어그램이란 객체의 행동 다이어그램 중 하나이다. 객체는 특정 상태를 지니며 이 상태는 이벤트와 같은 액션에 의하여 변경될 수 있다. 이러한 객체의 상태와 상태의 변화를 도식화 한 다이어그램이 객체 상태 다이어그램이다.
상태 패턴(state pattern)
상태패턴은 3가지로 구서된다.
- State(상태) - interface
상태가 변할 때마다 다른 동작을 하는 인터페이스(API)를 결정합니다.
- State(구체적인 상태) - 구현체
State의 인터페이스(API)를 구체적으로 구현합니다.
- Context(상황)
현재의 상태를 나타내는 ConcreteState 역할을 가집니다. 또한 State 패턴의 이용자에게 필요한 인터페이스(API)를 결정합니다.
구현
형광등을 끄고 키는 스위치가 있다고 하자.
형광등이 가지는 상태는
- 불 꺼짐
- 불 켜짐
이다.
해당 상태들은 사용자의 어떠한 행동에 따라서 변환되는데,
사용자가 할수있는 행동은
- 스위치 On
- 스위치 OFF
이다.
상태 패턴은 사용자의 행동에 따라서 형광등의 상태가 변하는 흐름을 미리 정해두고 사용할 수 있다.
public class Light { //Context
private State state;
public Light() {
state= new OffState(this);
}
public void setState(State state) {
this.state=state;
}
//state
public void onButton() {
this.state.onButton(this);
}
public void offButton() {
this.state.offButton(this);
}
}
public interface State {
public void onButton();
public void offButton();
}
//구체적인 구현체
public class OnState implements State {
Light light;
private OnState(Light light) {
this.light = light;
}
@Override
public void onButton() {
light.setState(OnState);
System.out.println("동작 없음");
}
@Override
public void offButton() {
light.setState(new OffState(light));
System.out.println("불 꺼짐!");
}
}
public class OffState implements State {
Light light;
private OffState(Light light) {
this.light = light;
}
@Override
public void onButton() {
light.setState(new OffState(light));
System.out.println("불 켜짐!");
}
@Override
public void offButton() {
System.out.println("동작 없음!");
}
}
상태 종류가 많아져도 계속 추가하기에 용이한 구조이다.
하지만, 상태가 변할때마다 new OffState(light)
처럼 새로 객체를 생성한다는 문제가 있다
뒷부분에서 싱글턴 패턴을 이용한 코드를 보면 좀더 이해하기 쉬울 것이다.
enum 활용
class Light {
public enum STATE { ON, OFF }
private STATE state = STATE.OFF;
public void onButtonPushed() {
if(state == STATE.ON) {
System.out.println("동작 없음");
} else {
System.out.println("불 켜짐!");
state = STATE.ON;
}
}
public void offButtonPushed() {
if(state == STATE.OFF) {
System.out.println("동작 없음");
} else {
System.out.println("불 꺼짐!");
state = STATE.OFF;
}
}
}
상태를 나타내는 대표적인 객체인 enum을 활용한 구현이다.
enum을 많이 쓰기 때문에 기존의 코드와 연계해서 사용하기 좋아보인다.
하지만, 지금의 구조에서는 상태 종류가 추가되면 if문의 갯수가 많아진다는 단점이 있다.
singleton 패턴 활용
class Light {
private State state = new StateOff();
public void setState(State state) {
this.state = state;
}
public void onButtonPushed () {
state.onButtonPushed(this);
}
public void offButtonPushed() {
state.offButtonPushed(this);
}
}
interface State {
void onButtonPushed(Light light);
void offButtonPushed(Light light);
}
class StateOff implements State {
private static StateOff instance = new StateOff();
public static State getInstance() {
return instance;
}
@Override
public void onButtonPushed(Light light) {
System.out.println("Turn on.");
light.setState(StateOn.getInstance());
}
@Override
public void offButtonPushed(Light light) {
System.out.println("Do nothing.");
}
}
public class StateOn implements State {
private static StateOn instance = new StateOn();
public static State getInstance() {
return instance;
}
@Override
public void onButtonPushed(Light light) {
System.out.println("Do sleeping");
light.setState(StateSleeping.getInstance());
}
@Override
public void offButtonPushed(Light light) {
System.out.println("Turn off");
light.setState(StateOff.getInstance());
}
}
class StateSleeping implements State {
private static StateSleeping instance = new StateSleeping();
public static State getInstance() {
return instance;
}
@Override
public void onButtonPushed(Light light) {
System.out.println("more brightly!");
light.setState(StateOn.getInstance());
}
@Override
public void offButtonPushed(Light light) {
System.out.println("Turn off this light.");
light.setState(StateOff.getInstance());
}
}
싱글턴 패턴을 이용해서 미리 생성한 객체를 사용하면 객체를 한번 생성하고 재사용 할 수 있다는 점과 상태가 공유되기 때문에 관리가 쉽다는 점에서 좀더 깔끔하게 구현할 수 있다.
전략 패턴과의 차이
- 전략 패턴
- 클라이언트가 어떤 전략을 사용할지 지정해줘야 한다.
- 사용자가 쉽게 알고리즘 전략을 바꿀 수 있도록 유연성 제공
- 상태 패턴
- 상태 객체의 일련의 행동이 캡슐화 되고, 그 객체의 내부 상태에 따라 현재 상태를 나타내는 객체가 바뀌게 되고, 자연스럽게 행동도 변경된다.
- 클라이언트는 객체의 상태에 대해서 아무것도 몰라도 된다.
Reference
http://icecola89.blogspot.com/2016/05/c.html
'JAVA' 카테고리의 다른 글
SpringBoot Controller 매개변수 애너테이션의 종류 (0) | 2021.10.05 |
---|---|
DAO와 repository의 차이 (0) | 2021.09.14 |
Proxy 객체 (0) | 2021.09.07 |
proxy 패턴 (0) | 2021.09.07 |
디자인 패턴 (0) | 2021.08.06 |