스테이트 패턴 (state pattern)

JAVA/Design Pattern|2018. 5. 28. 22:35

스테이트 패턴

객체의 상태를 효율적으로 관리 할 수 있도록 

스테이트 패턴을 알아보자

많은 개체들은 상태값이 변경됨에 따라 다른 일을 수행하게 된다.

이를 객체에 어떤 동작이 수행될 때마다 상태를 확인하고 그에 맞는 동작이 수행되도록 하는 경우

코드가 지저분해지고, 많은 switch, if문을 가지게 될 것이다.

이것을 스테이트 패턴을 이용하여 공통의 상태 인터페이스를 만든 후

각 상태에 따른 객체를 생성한 후 상세한 동작을 상태 객체에서 수행하도록 설정하는 것이다.

문제의 상황의 예를 살펴보자

기존의 객체의 상태값이 있는 경우 다음의 자동차 객체처럼 하는 경우가 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Car {
    private int ON = 1;
    private int OFF = 0;
    private int state;
    
    public Car() {
        // 시동이 꺼있는 상태 
        this.state = OFF;
    }
    
    public void onCar() {
        if (state != ON) {
            state = ON;
        }
    }
    
    public void offCar() {
        if (state != OFF) {
            state = OFF;
        }
    }
     
}
cs



하지만 만약에 시동이 켜진상태에서 다시한번 시동 버튼을 누를 경우
파워모드로 변경되고, 다시 시동버튼을 누르면 일반 모드로 넘어가도록 수정을 한다고 해보자.


다음과 같이 상태값 POWER_MODE_ON을 추가해야 하며,
onCar 메소드도 그에 따라 계속 변경되어야 한다.



1
2
3
4
5
6
7
8
9
10
11
private int POWER_MODE_ON = 2;
 
public void onCar() {
    if (state == ON) {
        this.state = POWER_MODE_ON;
    } else if (state == POWER_MODE_ON ) {
        this.state = ON; 
    } else if (state != ON) {
        state = ON;
    }
}

cs



상태값이 추가되거나 할 때마다 계속 수정된다면 매우 비효율 적이다.

해결방법

이를 해결하기 위해서는 현재 객체(Car)의 상태가 어떠하든지 상관없게 구성하고 
상태 변화에도 독립적 이도록 코드를 수정해야한다.

구성
- Car 객체는 별도의 상태를 나타내는 State를 구현한 객체를 보유한다.
- Car 객체에서 onCar, offCar 동작을 수행할 때마다 state에게 자신을 전달하여 상태를 변경한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class Car {
    // 자동차의 상태를 가지고 있는다.
    private CarState state;
    
    public Car() {
        // 시동이 꺼있는 상태를 기본으로 가지고 있는다.
        this.state = CarPowerOff.getInstance();
    }
    
    public CarState getState() {
        return state;
    }
 
    public void setState(CarState state) {
        this.state = state;
    }
 
    public void onCar() {
        this.state.on_buutton_pushed(this);
    }
    
    public void offCar() {
        this.state.off_button_pushed(this);
    }    
}
 
// 상태 객체를 구현하기 위한 인터페이스
public interface CarState {
    void on_buutton_pushed(Car car);
    void off_button_pushed(Car car);
}
 
// 시동 파워모드 On
public class CarPowerModeState implements CarState {
    
    private static CarPowerModeState instance = new CarPowerModeState();
    
    public static CarPowerModeState getInstance() {
        return instance;
    }
 
    @Override
    public void on_buutton_pushed(Car car) {
        car.setState(CarOneState.getInstance());
    }
 
    @Override
    public void off_button_pushed(Car car) {
        car.setState(CarPowerOff.getInstance());
    }
 
}
 
// 시동 On
public class CarOneState implements CarState {
    
    private static CarOneState instance = new CarOneState();
    
    public static CarOneState getInstance() {
        return instance;
    }
 
    @Override
    public void on_buutton_pushed(Car car) {
        car.setState(CarPowerModeState.getInstance());
    }
 
    @Override
    public void off_button_pushed(Car car) {
        car.setState(CarPowerOff.getInstance());
    }
 
}
 
// 시동 off
public class CarPowerOff implements CarState {
    private static CarPowerOff instance = new CarPowerOff();
    
    public static CarPowerOff getInstance() {
        return instance;
    }
    
    @Override
    public void on_buutton_pushed(Car car) {
        car.setState(CarOneState.getInstance());
    }
 
    @Override
    public void off_button_pushed(Car car) {
        // Not Work
    }
 
}
 
cs



결과적으로 위에 코드를 보면 알겠지만

결론
상태에 필요 부분을 인터페이스로 명세하고, 
상태별로 각자 필요 메소드를 Override하여 구현한다.

자동차는 현재 상태값을 객체 형태로 가지고 있으며, on 또는 off 요청이 들어왔을 때
현재 자신의 상태 객체에게 자신을 넘겨서 동작을 본인이 하는 것이아니라 현재 상태 객체에게 넘겨서
진행되도록 한다.



댓글()