GoFのデザインパターン
 Stateパターン編
        2013/03/01(金)
                伊藤歩
本日のアジェンダ
・デザインパターンとは
・Stateパターンの具体例
・Stateパターンのメリット
・デザインパターンの注意点
デザインパターンとは

過去のソフトウェア設計者が発見し
編み出した設計ノウハウを蓄積し、
名前をつけ、再利用しやすいように
特定の規約に従ってカタログ化したもので
ある。
              wikipediaより
過去のソフトウェア設計者
過去のソフトウェア設計者




       Gang of Four
  (ギャング・オブ・フォー、四人組)
Stateパターンの具体例サンプル

PLAY、STOP、PAUSEという状態がある

各状態で特定のコマンドを実行した時、
違う挙動をするプログラムを作成する。
if文で分岐させると・・・
// コマンドqを受け取った場合
if (s.equals("q")) {
     if (mState == STATE_PLAY) {
         System.out.println("STATE_PLAY:q");
     } else if (mState == STATE_STOP) {
         System.out.println("STATE_STO::q");
     } else if (mState == STATE_PAUSE) {
         System.out.println("STATE_PAUSE:q");
     }
}
if文で分岐させると・・・
// コマンドwを受け取った場合
if (s.equals("w")) {
     if (mState == STATE_PLAY) {
         System.out.println("STATE_PLAY:w");
     } else if (mState == STATE_STOP) {
         System.out.println("STATE_STOP:w");
     } else if (mState == STATE_PAUSE) {
         System.out.println("STATE_PAUSE:w");
     }
}
if文で分岐させると・・・
// コマンドeを受け取った場合
if (s.equals("e")) {
     if (mState == STATE_PLAY) {
         System.out.println("STATE_PLAY:e");
     } else if (mState == STATE_STOP) {
         System.out.println("STATE_STOP:e");
     } else if (mState == STATE_PAUSE) {
         System.out.println("STATE_PAUSE:e");
     }
}
さぁ野郎ども、
仕様追加のお時間だ!
さぁ野郎ども、
仕様追加のお時間だ!

コマンド”r”も追加な。
※全部の状態で。
そしてこうなる
// コマンドrを受け取った場合
if (s.equals("r")) {
     if (mState == STATE_PLAY) {
         System.out.println("STATE_PLAY:r");
     } else if (mState == STATE_STOP) {
         System.out.println("STATE_STOP:r");
     } else if (mState == STATE_PAUSE) {
         System.out.println("STATE_PAUSE:r");
     }
}
喜べ野郎ども、
また仕様追加だ!!!
喜べ野郎ども、
また仕様追加だ!!!

状態RECを追加な!
※全部のコマンドで
喜べ野郎ども、
また仕様追加だ!!!

状態RECを追加な!
※全部のコマンドで
状態×コマンド分の分岐が発生・・・




    if文地獄の
   幕開けである。
そんなときにStateパターン

状態をクラスとして設計。
そんなときにStateパターン

状態をクラスとして設計。

オブジェクトの状態に応じて、
挙動を変える場合に有効。
Stateパターンのクラス図
状態に応じたInterfaceを用意

public interface State {
  void func_q();
  void func_w();
  void func_e();
  void func_r();
}
Interfaceを実装する状態クラス作成
public class PlayState implements State {
    public void func_q(){
          System.out.println("STATE_PLAY:q");
    }
    public void func_w() {
          System.out.println("STATE_PLAY:w");
    }
    public void func_e() {
          System.out.println("STATE_PLAY:e");
    }
    public void func_r() {
          System.out.println("STATE_PLAY:r");
    }
}                                      StopやPauseも同様に、
                              StateのInterfaceを実装します。
状態によって、
オブジェクトを切り替える

State state = null;
if (n == STATE_PLAY) {
    state = new PlayState();
} else if (n == STATE_STOP) {
    state = new StopState();
} else if (n == STATE_PAUSE) {
    state = new PauseState();
}
あとはメソッドを呼ぶだけ
// コマンドに応じて処理を実行
if (s.equals("q")) {
    state.func_q();
}
if (s.equals("w")) {
    state.func_w();
}
if (s.equals("e")) {
    state.func_e();
}
Stateパターンのメリット

・コマンドや状態の追加で既存に影響ない。

・処理の修正は各Stateクラスで閉じる。

・コードの見通しが良くなる。

    影響範囲が少ないので、
    デバッグ工数が削減可能。
      保守性の向上。
デザインパターンの注意点

無理に導入しない。

Stateパターン使う俺カッコイイ(・∀・)
みたいなノリで、使うのはNG。

あくまでオブジェクトの状態に応じて、
挙動を変える場合に有効。

Gofのデザインパターン stateパターン編