Stateパターン
オブジェクト指向プログラミングでは、人や物をオブジェクトとして表現する。
Stateパターンでは、「状態」をオブジェクトで表現する。
状態はState
クラスとして表現され、Context
クラスが保持し、その状態に基づく振る舞いをする。
状態遷移(次にどの状態へなるか)は、各State
オブジェクト自身が知っている(設計方法により、Context
オブジェクトが管理する場合もある)。
Stateパターンは、オブジェクトの振る舞いがその「状態」に依存し、状態が変化することで振る舞いも変わる場合に有用。このパターンを使用すると、状態に基づく条件文(if-elseなど)を減少させ、コードの保守性と拡張性を向上させることができる。
シチュエーション
エアコンで温度の状態「低」「中」「高」を管理するものとする。
Stateパターンを使用しない場合
状態をクライアント自身が管理している。
状態が増えるたびにクライアント側のコードの修正が必要。
状態の追加や変更に対して柔軟性が低い。
Main.java
// クライアント
public class Main {
// 0:低 1:中 2:高
static int state = 1;
static void increase() {
if (state == 0) {
System.out.println("温度を「中」に上げます。");
state++;
} else if (state == 1) {
System.out.println("温度を「高」に上げます。");
state++;
} else if (state == 2) {
System.out.println("これ以上温度を上げることはできません。");
}
}
static void decrease() {
if (state == 0) {
System.out.println("これ以上温度を下げることはできません。");
} else if (state == 1) {
System.out.println("温度を「低」に下げます。");
state--;
} else if (state == 2) {
System.out.println("温度を「中」に下げます。");
state--;
}
}
public static void main(String[] args) {
decrease();
decrease();
increase();
increase();
increase();
decrease();
decrease();
// >> 温度を「低」に下げます。
// >> これ以上温度を下げることはできません。
// >> 温度を「中」に上げます。
// >> 温度を「高」に上げます。
// >> これ以上温度を上げることはできません。
// >> 温度を「中」に下げます。
// >> 温度を「低」に下げます。
}
}
Stateパターンを使用した場合
クライアントは状態の管理に関わらない。
Context
が、現在の状態に基づく振る舞いを提供し、「状態」自身が次の遷移先の状態を知っている。
Stateパターンでは、「状態」自身が次の遷移先を知っている。
新しい状態の追加や既存の状態の変更が局所的な変更で済む。
これにより、「クライアント」と「状態」間の結合が疎になる。
TemperatureState.java
// State
public interface TemperatureState {
void increase();
void decrease();
}
HighTemperatureState.java
// ConcreteState
public class HighTemperatureState implements TemperatureState {
// Context
AirConditioner airConditioner;
public HighTemperatureState(AirConditioner airConditioner) {
this.airConditioner = airConditioner;
}
@Override
public void increase() {
System.out.println("これ以上温度を上げることはできません。");
}
@Override
public void decrease() {
System.out.println("温度を「中」に下げます。");
// 次に遷移する状態を「状態」自身が知っている
airConditioner.setState(airConditioner.getMiddleState());
}
}
MiddleTemperatureState.java
// ConcreteState
public class MiddleTemperatureState implements TemperatureState {
// Context
AirConditioner airConditioner;
public MiddleTemperatureState(AirConditioner airConditioner) {
this.airConditioner = airConditioner;
}
@Override
public void increase() {
System.out.println("温度を「高」に上げます。");
// 次に遷移する状態を「状態」自身が知っている
airConditioner.setState(airConditioner.getHighState());
}
@Override
public void decrease() {
System.out.println("温度を「低」に下げます。");
// 次に遷移する状態を「状態」自身が知っている
airConditioner.setState(airConditioner.getLowState());
}
}
LowTemperatureState.java
// ConcreteState
public class LowTemperatureState implements TemperatureState{
// Context
AirConditioner airConditioner;
public LowTemperatureState(AirConditioner airConditioner){
this.airConditioner = airConditioner;
}
@Override
public void increase() {
System.out.println("温度を「中」に上げます。");
// 次に遷移する状態を「状態」自身が知っている
airConditioner.setState(airConditioner.getMiddleState());
}
@Override
public void decrease() {
System.out.println("これ以上温度を下げることはできません。");
}
}
AirConditioner.java
// Context
public class AirConditioner {
private TemperatureState highState;
private TemperatureState middleState;
private TemperatureState lowState;
TemperatureState state;
public AirConditioner() {
highState = new HighTemperatureState(this);
middleState = new MiddleTemperatureState(this);
lowState = new LowTemperatureState(this);
state = middleState;
}
public void increaseTemperature() {
state.increase();
}
public void decreaseTemperature() {
state.decrease();
}
void setState(TemperatureState state) {
this.state = state;
}
TemperatureState getHighState() {
return highState;
}
TemperatureState getMiddleState() {
return middleState;
}
TemperatureState getLowState() {
return lowState;
}
}
Main.java
// クライアント
public class Main {
public static void main(String[] args) {
AirConditioner airConditioner = new AirConditioner();
airConditioner.decreaseTemperature();
airConditioner.decreaseTemperature();
airConditioner.increaseTemperature();
airConditioner.increaseTemperature();
airConditioner.increaseTemperature();
airConditioner.decreaseTemperature();
airConditioner.decreaseTemperature();
// >> 温度を「低」に下げます。
// >> これ以上温度を下げることはできません。
// >> 温度を「中」に上げます。
// >> 温度を「高」に上げます。
// >> これ以上温度を上げることはできません。
// >> 温度を「中」に下げます。
// >> 温度を「低」に下げます。
}
}