Stateパターンは、GoFが提唱したデザインパターンの一つで、オブジェクトの状態に応じてその振る舞いを変更する設計手法です。
これにより、状態ごとの条件分岐がコードに散らばらず、状態ごとの処理が統一されて管理しやすくなります。
本記事では、Stateパターンの基本概念とそのメリット、使い方について解説し、Java、C++、C#による実装例を紹介します。
Stateパターンとは
Stateパターンは、オブジェクトが内部状態を持ち、その状態に応じて異なる振る舞いを行うパターンです。
状態の遷移が頻繁に行われるようなシステムにおいて、状態ごとに異なる処理を柔軟に切り替えることができます。
Stateパターンの概要
Stateパターンは、コンテキスト(Context)オブジェクトが内部の状態(State)を持ち、その状態に応じて異なる処理を委譲することで、振る舞いを変化させます。
状態の変化は、Stateオブジェクトによってカプセル化されるため、状態ごとの処理が個別に管理され、コンテキストクラスの複雑さが軽減されます。
Stateパターンのメリット
Stateパターンを使用することで、以下のようなメリットがあります。
Stateパターンの使い方
Stateパターンは、状態に応じた振る舞いが必要な場合や、状態遷移が複雑なシステムにおいて有効です。
主に次のようなシチュエーションで使用されます。
状態による処理の分岐
例えば、UIのコンポーネントが「非表示」「表示」「選択」のような複数の状態を持つ場合、各状態で異なる処理を行いたいときにStateパターンが役立ちます。
これにより、状態ごとの分岐がオブジェクト指向的に整理されます。
複雑な状態遷移の管理
システムが多くの状態遷移を持つ場合、各状態の振る舞いをStateパターンで管理することで、状態遷移に対する処理が容易になります。
また、状態ごとの処理が独立しているため、メンテナンスが容易です。
Stateパターン実装サンプル
以下では、Stateパターンの実装例をJava、C++、C#でそれぞれ示します。
各言語でのコードスタイルの違いを見ながら、Stateパターンがどのように動作するか確認してください。
JavaでのStateパターン実装
以下は、JavaでのStateパターンのサンプルです。
public interface State {
void doAction(Context context);
}
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";
}
}
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";
}
}
public class Context {
private State state;
public Context() {
state = null;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
}
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());
}
}
C++でのStateパターン実装
次に、C++での実装例です。
#include <iostream>
using namespace std;
class Context;
class State {
public:
virtual void doAction(Context* context) = 0;
};
class StartState : public State {
public:
void doAction(Context* context);
};
class StopState : public State {
public:
void doAction(Context* context);
};
class Context {
private:
State* state;
public:
Context() : state(nullptr) {}
void setState(State* state) {
this->state = state;
}
State* getState() {
return state;
}
};
void StartState::doAction(Context* context) {
cout << "Player is in start state" << endl;
context->setState(this);
}
void StopState::doAction(Context* context) {
cout << "Player is in stop state" << endl;
context->setState(this);
}
int main() {
Context* context = new Context();
StartState* startState = new StartState();
startState->doAction(context);
StopState* stopState = new StopState();
stopState->doAction(context);
delete startState;
delete stopState;
delete context;
return 0;
}
C#でのStateパターン実装
C#での実装例です。
using System;
public interface State {
void DoAction(Context context);
}
public class StartState : State {
public void DoAction(Context context) {
Console.WriteLine("Player is in start state");
context.SetState(this);
}
public override string ToString() {
return "Start State";
}
}
public class StopState : State {
public void DoAction(Context context) {
Console.WriteLine("Player is in stop state");
context.SetState(this);
}
public override string ToString() {
return "Stop State";
}
}
public class Context {
private State state;
public Context() {
state = null;
}
public void SetState(State state) {
this.state = state;
}
public State GetState() {
return state;
}
}
public class StatePatternDemo {
public static void Main(string[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.DoAction(context);
Console.WriteLine(context.GetState().ToString());
StopState stopState = new StopState();
stopState.DoAction(context);
Console.WriteLine(context.GetState().ToString());
}
}
まとめ
Stateパターンは、オブジェクトの状態に応じて振る舞いを変える設計手法であり、特に複雑な状態遷移を持つシステムにおいて効果を発揮します。
状態ごとの処理がカプセル化され、メンテナンス性と拡張性が向上します。
Java、C++、C#での実装サンプルを通じて、Stateパターンの具体的な使用方法とその利点を理解できたかと思います。
適切なデザインパターンを選択することで、システムの可読性や柔軟性が向上します。