State パターン

「State」という英単語は、「状態」を意味します。

このパターンでは、ある物についての各状態をそれに対応した各クラスで表現します。(つまり、状態1つにつき、クラス1つで表現します。)

通常、条件(状態)に一致するか否かの処理は、if文を使用し、コーディングしますが、その条件分岐数が多い場合、1つの条件で処理するコード量が多い場合、また同じ条件分岐が複数の箇所に点在する場合等、メンテナンスし辛いものとなってしまいます。しかし、このパターンを適用すると、その状態状態を個々のクラスで表現するため、単純明快となります。


役割り

1. State(状態)

状態を表すクラスです。

状態毎に振舞いが異なるメソッドのインタフェースを定義します。

2. ConcreteStateA・B(具体的な状態)

「State」のインタフェースを実装し、具体的な状態を、「1クラス」 = 「1状態」 で定義します。

1つ状態を表すのに複数のオブジェクトは必要ないため、「Singleton」パターンを適用します。

3. Context(状況判断)

現在の状態(「ConcreteStateA」か「ConcreteStateB」)を保持します。

利用者へのインタフェースを定義します。

状態を変更するメソッドを定義します。(状態の変更は、「ConcreteState」が次ぎの状態として相応しいものを判断し、この状態変更メソッドを呼出すことによって行います。)

4. Client(利用者)
「State」パターンを適用したクラスを用い処理を行います。

▲PageTop

クラス図

Stateパターンのクラス図

Stateパターン クラス図

▲PageTop

シーケンス図

Stateパターンのシーケンス図

Stateパターン シーケンス図

▲PageTop

サンプル

ソースコード

1. State.java

public interface State {
    public abstract void stateMethod1(Context context, int condition);
    public abstract void stateMethod2(Context context);
}

2. ConcreteStateA.java

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);
    }
}

3. ConcreteStateB.java

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);
    }
}

4. Context.java

public class Context {
    private State state = null;
    public Context() {
        state = ConcreteStateA.getInstance();
    }
    public void setState(State state) {
        this.state = state;
    }
    public void contextMethod1(int condition) {
        state.stateMethod1(this, condition);
    }
    public void contextMethod2() {
        state.stateMethod2(this);
    }
    public void contextMethod3(String msg) {
        System.out.println(msg);
    }
}

5. Client.java

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();
            System.out.println();
        }
    }
}

実行結果

C:\sample\desin_pattern\state>javac Client.java [Enter]

C:\sample\desin_pattern\state>java Client [Enter]
--------------------
0回目:3
     :1
☆☆☆☆☆ 状態変更 A -> B ☆☆☆☆☆
 状態:ConcreteStateB

--------------------
1回目:4
     :0
★★★★★ 状態変更 B -> A ★★★★★
 状態:ConcreteStateA

--------------------
2回目:4
     :0
 状態:ConcreteStateA

--------------------
3回目:7
     :1
☆☆☆☆☆ 状態変更 A -> B ☆☆☆☆☆
 状態:ConcreteStateB

--------------------
4回目:4
     :0
★★★★★ 状態変更 B -> A ★★★★★
 状態:ConcreteStateA

--------------------
5回目:6
     :0
 状態:ConcreteStateA

--------------------
6回目:4
     :0
 状態:ConcreteStateA

--------------------
7回目:7
     :1
☆☆☆☆☆ 状態変更 A -> B ☆☆☆☆☆
 状態:ConcreteStateB

--------------------
8回目:6
     :0
★★★★★ 状態変更 B -> A ★★★★★
 状態:ConcreteStateA

--------------------
9回目:4
     :0
 状態:ConcreteStateA
        

▲PageTop