State パターン

**State パターン**（、ステート・パターン）とは、プログラミングで用いられる デザインパターンの一種である。このパターンはオブジェクトの状態（state）を表現するために用いられる。ランタイムでそのタイプを部分的に変化させるオブジェクトを扱うクリーンな手段となる。

## 擬似コードによる例
ドローソフトを例に取る。このプログラムは任意の時点においてさまざまなツールのうちの1つとして振る舞うマウスカーソルを持つ。複数のカーソルオブジェクトを切り替える代わりに、カーソルは現在使用されているツールを表す内部的な状態を保持する。（例えばマウスクリックの結果として）ツールに依存するメソッドが呼ばれると、メソッド呼び出しはカーソルの状態へと渡される。

各ツールは1つの状態に対応している。共有される抽象状態クラスはAbstractToolである。

  **class** AbstractTool **is**
      **function** moveTo(point) **is**
          **input: ** the location *point* the mouse moved to
          *(this function must be implemented by subclasses)*
  
      **function** mouseDown(point) **is**
          **input: ** the location *point* the mouse is at
          *(this function must be implemented by subclasses)*
  
      **function** mouseUp(point) **is**
          **input: ** the location *point* the mouse is at
          *(this function must be implemented by subclasses)*

この定義により、各ツールはマウスカーソルの移動およびクリック／ドラッグの開始と終了を扱わなければならない。

その基底クラスを用い、単純なペンと範囲選択の各ツールを定義すると以下のようになる。

  **subclass** PenTool **of** AbstractTool **is**
      last_mouse_position := invalid
      mouse_button := up
  
      **function** moveTo(point) **is**
          **input: ** the location *point* the mouse moved to
          **if** mouse_button = down
              *(draw a line from the *last_mouse_position* to *point*)*
              last_mouse_position := point
  
      **function** mouseDown(point) **is**
          **input: ** the location *point* the mouse is at
          mouse_button := down
          last_mouse_position := point
  
      **function** mouseUp(point) **is**
          **input: ** the location *point* the mouse is at
          mouse_button := up
  
  
  **subclass** SelectionTool **of** AbstractTool **is**
      selection_start := invalid
      mouse_button := up
  
      **function** moveTo(point) **is**
          **input: ** the location *point* the mouse moved to
          **if** mouse_button = down
              *(select the rectangle between *selection_start* and *point*)*
  
      **function** mouseDown(point) **is**
          **input: ** the location *point* the mouse is at
          mouse_button := down
          selection_start := point
  
      **function** mouseUp(point) **is**
          **input: ** the location *point* the mouse is at
          mouse_button := up

この例では、コンテキストのためのクラスはCursorと呼ばれている。抽象状態クラス（この場合AbstractTool）で名付けられたメソッド群はコンテキストにおいても実装されている。コンテキストクラスではこれらのメソッドは、current_toolにより表される現在の状態の、対応するメソッドを呼び出す。

  **class** Cursor **is**
      current_tool := **new** PenTool
  
      **function** moveTo(point) **is**
          **input: ** the location *point* the mouse moved to
          current_tool.moveTo(point)
  
      **function** mouseDown(point) **is**
          **input: ** the location *point* the mouse is at
          current_tool.mouseDown(point)
  
      **function** mouseUp(point) **is**
          **input: ** the location *point* the mouse is at
          current_tool.mouseUp(point)
  
      **function** usePenTool() **is**
          current_tool := **new** PenTool
  
      **function** useSelectionTool() **is**
          current_tool := **new** SelectionTool

Cursorオブジェクトが、適切なメソッド呼び出しをアクティブとなっているツールへと渡すことにより、異なる時点においてPenToolとSelectionToolのどちらとしてでも振舞えるのである。これが**Stateパターン**の本質である。この場合では、PenCursorクラスとSelectCursorクラスを作ることで状態とオブジェクトを結合することも可能であり、単なる継承へと単純化できたであろうが、実践においては新しいツールが選択される毎に新しいオブジェクトへとコピーするにはコストがかかりすぎたりエレガントでなかったりするようなデータをCursorが保持していることもあるであろう。

## Javaによる例

以下は状態（State）のインタフェースと2つの実装である。状態メソッドはコンテキストオブジェクトへの参照を持ち、その状態を変えることができる。


```java
interface State {
	void writeName(StateContext stateContext, String name);
}

class StateA implements State {
	public void writeName(StateContext stateContext, String name) {
		System.out.println(name.toLowerCase());
		// コンテキストをStateBに遷移する
		stateContext.setState(new StateB());
	}
}

class StateB implements State {
	private int count = 0;
	public void writeName(StateContext stateContext, String name){ 
		System.out.println(name.toUpperCase()); 
		// StateBのwriteName()が2度呼び出された後にコンテキストをStateAに遷移する
		if (++count > 1) { 
			stateContext.setState(new StateA()); 
		}
	}
}
```


コンテキストクラスは、初期状態（この場合はStateA）でインスタンス生成したところの状態変数を持つ。そのメソッドでは、状態オブジェクトの対応するメソッドを使用する。


```java
public class StateContext {
	private State myState;
	public StateContext() {
		setState(new StateA());
	}

	// 通常は、Stateインタフェースを実装しているクラスによってのみ呼び出される
	public void setState(State newState) {
		this.myState = newState;
	}

	public void writeName(String name) {
		this.myState.writeName(this, name);
	}
}
```


用法は以下。

```java
public class TestClientState {
	public static void main(String[] args) {
		StateContext sc = new StateContext();
		sc.writeName("Monday");
		sc.writeName("Tuesday");
		sc.writeName("Wednesday");
		sc.writeName("Thursday");
		sc.writeName("Saturday");
		sc.writeName("Sunday");
	}
}
```


TestClientStateからのmain()の出力は次のようになるはずである。

```text
monday
TUESDAY
WEDNESDAY
thursday
SATURDAY
SUNDAY
```


## 脚注

## 関連項目
* 有限オートマトン
* Strategy パターン

## 外部リンク
* State Design Pattern