상태 패턴

이정석·2023년 6월 23일
0

디자인패턴

목록 보기
19/23

상태 패턴이란?

객체의 내부 상태가 변경되었을 때 객체의 행동도 변할수 있도록 하는 패턴으로 '상태'를 객체로 만들어 '상태 객체'를 변경함으로 행동을 변경하는 패턴이다.


문제상황

신호등은 RED, GREEN, YELLOW 상태가 있다.
1. TrafficLight 클래스는 다음과 같다.

public class TrafficLight {
    private String state;

    public TrafficLight() {
        state = "RED";
    }

    public void changeState() {
        if ("RED".equals(state)) {
            state = "GREEN";
            System.out.println("RED State");
        } else if ("GREEN".equals(state)) {
            state = "YELLOW";
            System.out.println("GREEN State");
        } else if ("YELLOW".equals(state)) {
            state = "RED";
            System.out.println("YELLOW State");
        }
    }
}

위 상황에서 새로운 상태나 기존 상태가 수정될 때, 상태 전이 흐름이 바뀔 때 기존의 TrafficLight 클래스를 수정해야 한다.

객체의 상태를 또 다른 객체로 만들어 기존 객체의 상태변화와 행동을 '상태 객체'에 위임하자


구조

  1. State: 모든 ConcreteState의 공통된 인터페이스를 나타내는 클래스로 State는 Context가 요청한 작업을 정의하고 실행하는 메소드를 선언한다.
  2. ConcreteState: Context가 요청한 작업을 실제로 수행하는 과정을 구현한 코드로 실제 객체의 특정 상태를 의미한다.
  3. Context: 현재 상태를 나타내는 State 변수와 시스템의 상태를 구성하는 변수를 가지는 클래스로 request요청을 받으면 실제 행위를 실행하는 대신 State 변수에 행위 실행을 위임한다.

코드(JAVA)

1. State

interface State {
    void changeState(TrafficLight trafficLight);
}

2. Red, Green, Yellow State

class RedState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("RED State");
        trafficLight.setState(new GreenState());
    }
}

class GreenState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("GREEN State");
        trafficLight.setState(new YellowState());
    }
}

class YellowState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("YELLOW State");
        trafficLight.setState(new RedState());
    }
}

3. TrafficLight

class TrafficLight {
    private State state;

    public TrafficLight() {
        state = new RedState();
    }

    public void setState(State state) {
        this.state = state;
    }

    public void changeState() {
        state.changeState(this);
    }
}

Client는 Context(TrafficLight)객체를 초기화 하는 것 외에는 상태 변환에 직접적인 개입을 하지 않는다. 패턴이 적용된 코드에서 상태추가, 상태수정, 상태전이변경과 같은 작업을 수행한다면 Context가 아닌 ConcreteState에 해당하는 클래스를 변경이 필요하다.


상태변환은 어떻게?

상태변환은 다음과 같은 단계로 진행된다.

  1. Context 객체가 ConcreteState의 handle 함수를 호출할 때 Context의 Reference를 인자로 넘긴다.
  2. Reference를 받은 ConcreteState는 Context의 setState를 통해 상태를 변화 시킨다.
  3. 상태를 변화시키기전에 상태의 행동에 해당하는 연산을 수행할 수 있다.

아래 코드를 보면 changeState라는 함수의 인자로 Reference를 받고 상태에 해당하는 행동(print)를 한뒤 setState로 Context의 상태를 변화시킨다.

class RedState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("RED State");
        trafficLight.setState(new GreenState());
    }
}

싱글톤 패턴의 적용

아래 코드를 보면 상태전이를 할 때 setState(new ConcreteState())의 형태로 진행하는데 이것은 상태전이를 할 때마다 새로운 객체를 생성한다는 의미이다.

class RedState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("RED State");
        trafficLight.setState(new GreenState());
    }
}

class GreenState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("GREEN State");
        trafficLight.setState(new YellowState());
    }
}

class YellowState implements State {
    public void changeState(TrafficLight trafficLight) {
        System.out.println("YELLOW State");
        trafficLight.setState(new RedState());
    }
}

이를 해결하기 위해서 ConcreteState의 객체의 인스턴스를 하나만 유지할 필요가 있다.

객체의 인스턴스를 하나만 유지하기 위해서 싱글톤패턴을 적용한다.

아래 코드는 싱글톤패턴을 적용한 RedState의 코드이며 다른 Green, Yellow도 같은 방식으로 ConcreteState의 인스턴스를 하나만 유지할 수 있다.

class RedState implements State {
    private static RedState instance = null;

    private RedState() {}

    public static RedState getInstance() {
        if (instance == null) {
            instance = new RedState();
        }
        return instance;
    }

    public void changeState(TrafficLight trafficLight) {
        System.out.println("RED State");
        trafficLight.setState(GreenState.getInstance());
    }
}
profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글