ステートパターン

ステートパターン(State Pattern)では、クラスの動作はその状態に基づいて変化します。このタイプのデザインパターンは振る舞い型パターンに属します。

ステートパターンでは、さまざまな状態を表すオブジェクトと、状態オブジェクトの変更に応じて動作が変わる context オブジェクトを作成します。

ステートパターンは、オブジェクトが内部状態の変化に応じてその動作を変更できるようにし、異なる状態で異なる動作を示すようにします。各状態を独立したクラスにカプセル化することで、状態遷移を実装するための大量の条件文を回避できます。

紹介

意図

オブジェクトがその内部状態の変化に応じて動作を変更できるようにし、あたかもクラスが変わったかのように見せます。

主に解決する問題

  • ステートパターンは、オブジェクトの動作がその状態に依存する問題を解決し、状態が変化したときにオブジェクトが動作を切り替えられるようにします。

使用シーン

  • コード内に大量の条件文が存在し、それらの条件文がオブジェクトの状態に依存している場合。

実装方法

  • 状態インターフェースを定義する:1つ以上のメソッドを宣言し、具体的な状態の動作をカプセル化します。
  • 具象状態クラスを作成する:状態インターフェースを実装し、状態に応じて具体的な動作を実装します。
  • コンテキストクラスを定義する:状態オブジェクトの参照を保持し、状態が変化したときにその動作を更新します。

重要なコード

  • 状態インターフェース:動作メソッドを宣言します。
  • 具象状態クラス:状態インターフェースを実装し、具体的な動作をカプセル化します。
  • コンテキストクラス:状態オブジェクトを保持し、その状態を変更するためのメソッドを提供します。

応用例

  • バスケットボール選手の状態:選手には通常、異常、超常などの状態があります。
  • 曽侯乙編鐘:編鐘をコンテキストとして、異なる鐘(状態)は異なる演奏効果を持ちます。

長所

  • 状態遷移ルールをカプセル化する:状態遷移ロジックを状態オブジェクト内部にカプセル化します。
  • 拡張が容易:新しい状態クラスを追加しても、既存のコードに影響を与えません。
  • 状態に関連する動作の集中化:特定の状態に関連するすべての動作を1つのクラスに集中させます。
  • 条件文の簡素化:動作を切り替えるために大量の条件文を使用することを避けます。
  • 状態の共有:複数のコンテキストオブジェクトが同じ状態オブジェクトを共有できるようにします。

短所

  • クラスとオブジェクトの数が増加する:各状態に具象状態クラスが必要です。
  • 実装が複雑:パターンの構造と実装が比較的複雑です。
  • 開放閉鎖原則のサポートが不十分:新しい状態の追加や状態の動作の変更には、既存のコードの修正が必要になる場合があります。

使用上のアドバイス

  • オブジェクトの動作が状態の変化に応じて変わる場合は、ステートパターンの使用を検討してください。
  • ステートパターンは、複雑な条件文や分岐文の代替に適しています。

注意事項

  • ステートパターンは、状態の数が有限(通常5つ以下)の場合に適しています。
  • システムが過度に複雑にならないよう、慎重に使用してください。

構造

ステートパターンには、以下の主要な役割が含まれます。

  • コンテキスト(Context):クライアントが関心を持つインターフェースを定義し、現在の状態オブジェクトへの参照を保持します。コンテキストは状態オブジェクトを介して状態に関連する動作の処理を委譲できます。

  • 状態(State):コンテキストに関連するある状態の動作をカプセル化するためのインターフェースを定義します。

  • 具象状態(Concrete State):状態インターフェースを実装し、その状態に関連する動作の処理を担当します。具象状態オブジェクトは通常、内部にコンテキストオブジェクトへの参照を保持し、さまざまな条件に応じて異なる状態に切り替えられるようにします。

実装

私たちは作成しますStateインターフェースと、それを実装したStateインターフェースの具象状態クラス。Contextある状態を持つクラスです。

StatePatternDemo私たちのデモクラスは使用しますContextContext と状態オブジェクトで、Context の状態が変わるときの動作の変化をデモします。

状态模式的 UML 图

ステップ 1

インターフェースを作成します。

State.java

public interface State { public void doAction(Context context); }

ステップ 2

インターフェースを実装する具象クラスを作成します。

StartState.java

public class StartState implements State { public void doAction(Context context) { System.out.println("Player is in start state"); context.setState(this); } public String toString(){ return "Start State"; } }

StopState.java

public class StopState implements State { public void doAction(Context context) { System.out.println("Player is in stop state"); context.setState(this); } public String toString(){ return "Stop State"; } }

ステップ 3

作成するContextクラス。

Context.java

public class Context { private State state; public Context(){ state = null; } public void setState(State state){ this.state = state; } public State getState(){ return state; } }

ステップ 4

使用するContextことで、状態がState変わるときの動作の変化を確認します。

StatePatternDemo.java

public class StatePatternDemo { public static void main(String[] args) { Context context = new Context(); StartState startState = new StartState(); startState.doAction(context); System.out.println(context.getState().toString()); StopState stopState = new StopState(); stopState.doAction(context); System.out.println(context.getState().toString()); } }

ステップ 5

プログラムを実行し、結果を出力します:

Player is in start state
Start State
Player is in stop state
Stop State

その他の記事

その他の拡張