Stateパターンとは
Stateパターンは、オブジェクトの状態を独立したクラスとして表現し、実行時にオブジェクトの振る舞いを変更できるようにするデザインパターンです。このパターンは、特にオブジェクトの状態が複雑に変化する場合や、状態に応じて異なる処理を実行する必要がある場合に有効です。
Stateパターンの目的
Stateパターンの主な目的は以下の通りです。
状態の管理の分離: オブジェクトの状態を個別のクラスにカプセル化することで、状態遷移のロジックを明確にし、コードの可読性と保守性を向上させます。
動的な振る舞いの変更: オブジェクトの内部状態を変更することで、実行時にその振る舞いを動的に変更できるようにします。
コードの複雑さの軽減: 状態に応じた条件分岐を減らし、コードの複雑さを軽減します。
Stateパターンの構成要素
Stateパターンは、以下の要素で構成されます。
Context: 状態を持つオブジェクト。現在の状態を保持し、状態オブジェクトに処理を委譲します。
State: 状態を表すインターフェースまたは抽象クラス。状態オブジェクトが実装する共通のインターフェースを定義します。
ConcreteState: Stateインターフェースを実装する具体的な状態クラス。それぞれの状態における振る舞いを定義します。
Stateパターンの例:ドローソフトのマウスカーソル
ドローソフトのマウスカーソルを例に、Stateパターンを適用してみましょう。
この例では、マウスカーソルが持つ状態として、以下の2つを考えます。
ペンツール: 線を描画する状態。
選択ツール: 領域を選択する状態。
各状態は、AbstractToolクラスを継承し、moveTo, mouseDown, mouseUpメソッドを実装します。
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)
PenToolクラス
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
SelectionToolクラス
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クラス
CursorクラスはContextとして機能し、現在のツール(状態)を保持し、マウスイベントを適切な状態オブジェクトに委譲します。
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オブジェクトは、usePenToolやuseSelectionToolメソッドを呼び出すことで、内部の状態を動的に変更し、ペンツールや選択ツールとしての振る舞いを切り替えることができます。この動的な振る舞いの切り替えがStateパターンの本質です。
StateパターンとStrategyパターンの違い
Stateパターンは、Strategyパターンと似ていますが、以下の点が異なります。
Stateパターン: オブジェクトの内部状態を変更し、その状態に応じて振る舞いを変更します。状態遷移が重要です。
Strategyパターン: アルゴリズムを選択するために使用されます。コンテキストは、異なる戦略を切り替えることができます。
まとめ
Stateパターンは、オブジェクトの状態をクラスとして表現することで、コードの可読性、保守性を向上させ、より柔軟なプログラム設計を可能にする強力なデザインパターンです。状態遷移が複雑な場合に、このパターンを採用することで、コードの整理と管理が容易になります。