どんなもの?
- 状態が変わったときに、オブジェクトの振る舞いが変わるようにする。
- それぞれの状態をクラスで表現する。
- 状態を持つクラスは、それぞれの状態クラスを抽象クラスの形で保持する。
- オブジェクト指向ステートマシン
- Wrapper + polymorphic wrappee + collaboration
どんなときに使う?
- 条件(状態)に一致するか否かを判定してそれぞれ処理したいとき。
特に以下の場合に有効
- 条件分岐数が多いとき
- 同じ条件分岐が複数の箇所に点在するとき
例
典型的な構成要素
- State
- 状態を表すクラス
- 状態ごとに振る舞いが異なる関数のインターフェースを定義する
- ConcreteStateA
- ConcreteStateB
- Stateのインターフェースを実装する
- 具体的な状態を1クラス=1状態で定義する
- 1つの状態を表すのに複数のオブジェクトは必要ないため、Singletonを適用する
- Context(状況判断)
- 現在の状態を保持する
- 利用者へのインターフェースを定義する
- 状態を変更する関数を定義する
- Client
コード
#include <iostream>
#include <string>
using namespace std;
class Context;
class State{
public:
virtual void stateMethod1(Context* context, int condition) = 0;
virtual void stateMethod2(Context* context) = 0;
};
class Context{
public:
Context(State* state){
this->state = state;
}
void setState(State *state){
this->state = state;
}
void contextMethod1(int condition){
state->stateMethod1(this, condition);
}
void contextMethod2(){
state->stateMethod2(this);
}
void contextMethod3(string msg){
cout << msg << endl;
}
private:
State *state;
};
class ConcreteStateA: public State{
public:
static State* getInstance(){
static ConcreteStateA concretestateA;
return &concretestateA;
}
private:
ConcreteStateA(){}
void stateMethod1(Context* context, int condition){
if(condition == 1){
}
}
void stateMethod2(Context* context){
context->contextMethod3("test() at ConcreteStateA");
}
};
class ConcreteStateB: public State{
public:
static State* getInstance(){
static ConcreteStateB concretestateB;
return &concretestateB;
}
private:
ConcreteStateB(){}
void stateMethod1(Context* context, int condition){
if(condition == 0){
context->setState(ConcreteStateA::getInstance());
}
}
void stateMethod2(Context* context){
context->contextMethod3("test() at ConcreteStateB");
}
};
int main(){
Context* context = new Context(ConcreteStateA::getInstance());
for(int i=0;i<5;i++){
context->contextMethod1(i%2);
context->contextMethod2();
}
}