[Design Pattern] GoF 생성 패턴 - 상태 패턴(State Pattern)



상태 패턴(State Pattern)

GoF 디자인 패턴 중 행동 패턴에 해당한다.
상태 패턴은 객체가 가지고 있는 내부 상태에 따라 스스로 행동을 변경할 수 있게 하는 패턴이다. 상태를 표현하는 추상 클래스나 인터페이스를 만들고, 상태 객체를 내부에 가지게 된다.


사용법

  • 객체의 행동이 상태에 따라 달라질 수 있고, 객체 상태에 따라 런타임에 행동이 바뀌어야 할 때
  • 상태에 따라 달라지는 분기 처리가 많을 때


구조

img

  • 행동을 가진 객체 Context는 State의 인스턴스를 유지하고 관리한다.
  • 상태별로 필요한 행동을 캡슐화하여 State추상클래스/인터페이스를 정의한다.
  • ConcreteState서브클래스들은 Context의 상태에 따라 처리되어야 할 실제 행동을 구현한다.


장점

  • 상태에 따른 행동을 국소화하여 상태에 대한 행동을 별도 객체로 관리함
  • 상태별로 객체를 만들어줌으로써 상태 변화를 명백하게 함1

:bulb: 1: 상태를 내부 데이터 값으로만 표현하면 단지 상태 변수에 값을 할당하는 것에 불과함.


구현 시 주의할 점

상태 패턴 구현에 신경써야하는 부분 중 첫번째는 상태 전이를 결정하는 주체이다. 일반적으로는 ConcreteState 클래스들이 자신 다음에 나오는 상태가 무엇이고 상태 전이가 언제 될지를 정하도록 만든다. 이 방법의 단점으로는 ConcreteState 클래스가 자신 다음에 나오는 다른 ConcreteState를 알아야 해서 서브클래스들끼리 종속성이 생길 수 있다는 것이다.

두번째는 상태 객체의 생성과 소멸 시점이다. (1)상태 객체를 필요할 때만 생성하고 필요없으면 없애는 방법(2)미리 만들어 놓고 계속 두는 방법이 있다. (1)의 방법은 상태 객체가 많은 정보를 담고 있는 경우에 유용하다. (2)의 방법은 상태 변화가 수시로 일어날 때 좋은 방법이다.


예제

클래스 다이어그램

img


구현

HandHeldFan handHeldFan = new HandHeldFan();
System.out.println("손풍기 샀다!! 작동 시켜볼까?\n");
for(int i=0;i<6;i++){
    System.out.print("딸깍 -> ");
    handHeldFan.clickButton();
}
[실행 결과]
손풍기 샀다!! 작동 시켜볼까?

딸깍 -> 약한 바람이 부는 중입니다.. 휘잉..
딸깍 -> 강한 바람이 부는 중입니다!!! 휘잉!! 휘잉!! 휘이잉!!!!
딸깍 -> 손풍기가 작동 중이 아닙니다.
딸깍 -> 약한 바람이 부는 중입니다.. 휘잉..
딸깍 -> 강한 바람이 부는 중입니다!!! 휘잉!! 휘잉!! 휘이잉!!!!
딸깍 -> 손풍기가 작동 중이 아닙니다.


소스 코드

전체 소스 코드

package main;

import fan.HandHeldFan;

public class Main {
    public static void main(String[] args) {
        HandHeldFan handHeldFan = new HandHeldFan();
        System.out.println("손풍기 샀다!! 작동 시켜볼까?\n");
        for(int i=0;i<6;i++){
            System.out.print("딸깍 -> ");
            handHeldFan.clickButton();
        }
    }
}
package fan.state;

import fan.HandHeldFan;

public interface State {
    void wind(HandHeldFan fan);
}
package fan;

import fan.state.State;
import fan.state.WeakState;

public class HandHeldFan {
    private State state;

    public HandHeldFan() {
        changeState(WeakState.getInstance());
    }

    public void clickButton() {
        state.wind(this);
    }

    public void changeState(State state){
        this.state = state;
    }
}
package fan.state;

import fan.HandHeldFan;

public class OffState implements State {
    private static OffState _instance;

    public static OffState getInstance() {
        if (_instance == null)
            _instance = new OffState();
        return _instance;
    }

    @Override
    public void wind(HandHeldFan fan) {
        System.out.println("손풍기가 작동 중이 아닙니다.");
        fan.changeState(WeakState.getInstance());
    }
}
package fan.state;

import fan.HandHeldFan;

public class WeakState implements State{
    private static WeakState _instance;

    public static WeakState getInstance() {
        if (_instance == null)
            _instance = new WeakState();
        return _instance;
    }

    @Override
    public void wind(HandHeldFan fan) {
        System.out.println("약한 바람이 부는 중입니다.. 휘잉..");
        fan.changeState(StrongState.getInstance());
    }
}
package fan.state;

import fan.HandHeldFan;

public class StrongState implements State{
    private static StrongState _instance;

    public static StrongState getInstance() {
        if (_instance == null)
            _instance = new StrongState();
        return _instance;
    }
    @Override
    public void wind(HandHeldFan fan) {
        System.out.println("강한 바람이 부는 중입니다!!! 휘잉!! 휘잉!! 휘이잉!!!!");
        fan.changeState(OffState.getInstance());
    }
}



:bookmark: REFERENCE
에릭 감마 외 3명, 「GoF의 디자인 패턴」, 피어슨에듀케이션코리아