[State] = [状態] を意味する.
このパターンでは, ある物についての各状態をそれ対応した各クラスで表現する. (つまり, 状態一つにつき, クラス1つで表現する)
通常, 条件 (状態) に一致するかどうかの処理は, if 文を使用し, コーディングするが, その条件分岐が多い場合, 1つの条件で処理するコード量が多い場合, また同じ条件分岐が複数の個所に点在する場合など, メンテナンスしづらいものとなってしまう. しかし, このパターンを適用すると, その状態を個々のクラスで表現するため, 単純明快となる.
状態を表すクラスである. 状態毎に振る舞いがことなるメソッドのインタフェースを定義する.
[State] のインタフェースを実装し, 具体的な状態を [1 クラス] = [1 状態] で定義する. 1つ状態を表すのに複数のオブジェクトは必要ないため, [Singleton] パターンを適用する.
現在の状態 ( [ConcreteStataA] か [ConcreteStateB] ) を保持する. 利用者へのインタフェースを定義する. 状態を変更するメソッドを定義する. (状態の変更は, [ConcreteState] が次々の状態として相応しいものを判断し, この状態変更メソッドを呼び出すことによって行う.)
[State] パターンを適用したクラスを用い処理を行う.
1 2 3 4 | public interface State{
public abstract void stateMethod1(Context context, int condition);
public abstract void stateMethod2(Context context);
}
|
2-1. ConcreteStateA.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class ConcreteStateA implements State{
private static final String stateName = "ConcreteStateA";
/* [Singleton] パターンを適用 */
private static State concreteStateA = new ConcreteStateA();
private ConcreteStateA(){}
public static State getInstance(){
return concreteStateA;
}
/* [Context] が参照しているアクティブな [State] オブジェクト変更用メソッド */
public void stateMethod1(Context context, int condition){
if(condition == 1){
context.setState(ConcreteStateB.getInstance());
System.out.println("状態変更: A -> B");
}
}
public void stateMethod2(Context context){
context.contextMethod3("状態: " + stateName);
}
}
|
2-2. ConcreteStateB.java
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 ConcreteStateB implements State{
private static final String stateName = "ConcreteStateB";
/* [Singleton] パターンを適用 */
private static State concreteStateB = new ConcreteStateB();
private ConcreteStateB(){}
public static State getInstance(){
return concreteStateB;
}
/* [Context] が参照しているアクティブな [State] オブジェクト変更用メソッド */
public void stateMethod1(Context context, int condition){
if(condition == 0){
context.setState(ConcreteStateA.getInstance());
System.out.println("状態変更: B -> A");
}
}
public void stateMethod2(Context context){
context.contextMethod3("状態: " + stateName);
}
}
|
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 Context{
private State state = null;
public Context(){
state = ConcreteStateA.getInstance();
}
public void setState(State state){
this.state = state;
}
public void contextMethod1(int conditon){
state.stateMethod1(this, conditon);
}
public void contextMethod2(){
state.stateMethod2(this);
}
public void contextMethod3(String msg){
System.out.println(msg);
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import java.util.Random;
public class Client{
public static void main(String[] args){
Random rand = new Random();
Context context = new Context();
int temp = 0;
int condition = 0;
for (int i = 0; i < 10; i++){
System.out.println("--------------------");
temp = rand.nextInt(10);
System.out.println(i + " 回目: " + temp);
condition = temp % 2;
System.out.println(" : " + condition);
context.contextMethod1(condition);
context.contextMethod2();
}
}
}
|
上記のプログラムの実行結果:
[wtopia State]$ java Client
--------------------
0 回目: 1
: 1
状態変更: A -> B
状態: ConcreteStateB
--------------------
1 回目: 4
: 0
状態変更: B -> A
状態: ConcreteStateA
--------------------
2 回目: 7
: 1
状態変更: A -> B
状態: ConcreteStateB
--------------------
3 回目: 0
: 0
状態変更: B -> A
状態: ConcreteStateA
--------------------
4 回目: 1
: 1
状態変更: A -> B
状態: ConcreteStateB
--------------------
5 回目: 9
: 1
状態: ConcreteStateB
--------------------
6 回目: 3
: 1
状態: ConcreteStateB
--------------------
7 回目: 9
: 1
状態: ConcreteStateB
--------------------
8 回目: 6
: 0
状態変更: B -> A
状態: ConcreteStateA
--------------------
9 回目: 0
: 0
状態: ConcreteStateA
上記のプログラムの状態遷移図は下記のようになる.