デザインパターン学習メモ:「State」


目的

GoF本より引用する。

オブジェクトの内部状態が変化したときに、オブジェクトが振る舞いを変えるようにする。クラス内では、振る舞いの変化を記述せず、状態を表すオブジェクトを導入することでこれを実現する。(P.325)

オブジェクトの内部状態が変化した時の振る舞いの変化をクラス内で記述した場合、if文もしくはswitch文でクラスの状態を判断し、処理を切り替える実装をすることになる。

この方法ではコードは読み難くく、また、内部状態のパターンが追加されるたびにコードが複雑化していく。

そこで、内部状態をそれぞれクラスとして表現し、状態によって処理が異なる場合は、そのクラスに委譲する。

Strategyパターンとよく似ている。
http://qiita.com/mokrai/items/2caf83112c4b92d2ebe7

実装例

ボタンの例。スイッチを押すと仕事を実行する。もう一度押すとストップする。
スイッチオンの状態とオフの状態を別々のクラスで表現している。

Button.java
// Context役
public class Button {
    private static final State onState = new OnState();
    private static final State offState = new OffState();
    private State state = offState;

    public void push() {
        state.push(this);
    }

    public void setOff() {
        this.state = offState;
    }

    public void setOn() {
        this.state = onState;
    }

    public void execute() {
        // do something...
    }

    public void stop() {
        // stop something...
    }
}
State.java
// State役
public interface State {
    void push(Button button);
}
OffState.java
// ConcreteState役
public class OffState implements State {

    @Override
    public void push(Button button) {
        System.out.println("スイッチ オン!");
        button.setOn();  // Context役の状態変化はState役(ConcreteState)で実施
        button.execute();
    }
}
OnState.java
// ConcreteState役
public class OnState implements State {

    @Override
    public void push(Button button) {
        System.out.println("スイッチ オフ!");
        button.setOff();  // Context役の状態変化はState役(ConcreteState)で実施
        button.stop();
    }
}

その他の実装例

『アジャイルソフトウェア開発の奥義』にでてくる改札口の例がわかりやすい。

改札がロック状態(閉じている状態)とアンロック状態(通過可能な状態)をStateとして表現している。

参考文献

  • ロバート・C・マーチン(2004)『アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技』瀬谷啓介訳、SBクリエイティブ
  • エリック ガンマ、ラルフ ジョンソン、リチャード ヘルム、ジョン プリシディース(1999)『オブジェクト指向における再利用のためのデザインパターン 改訂版』本位田 真一、吉田 和樹 監訳、SBクリエイティブ