StateパターンおよびContextのインターフェイス 続き

Contextをインターフェイスにする例。

時間経過と共に色が最大3段階変化する電灯をStateパターンで実装してみる。


電灯のコンテキストのインターフェイスクラス

class LightState;

class LightContext {
public:
    virtual ~LightContext() {}

    // 状態を遷移させる
    virtual LightState* ChangeState( LightState* nextState ) = 0;

    // 時間経過を行う
    virtual void PassTime( time_t timePassed ) = 0;

    // 色を表示する
    virtual void PrintColor() = 0;
};


電灯の状態のインターフェイスクラス

class LightContext;

class LightState {
public:
    virtual ~LightState() {}

    // 時間経過を行う
    virtual void PassTime( LightContext* context, time_t timePassed ) = 0;

    // 色を出力する
    virtual void PrintColor() = 0;
};

一つ目の電灯の状態

class FirstLightState : public LightState {
private:
    time_t m_timePassed;

    static FirstLightState* instance;

    FirstLightState();
public:
    ~FirstLightState();

    static FirstLightState* Instance();

    // 2秒経過したら次の状態に遷移する
    void PassTime( LightContext* context, time_t timePassed );

    // 赤を表示する
    void PrintColor();
};

2つ目の電灯の状態

class SecondLightState : public LightState {
private:
    time_t m_timePassed;

    static SecondLightState* instance;

    SecondLightState();
public:
    ~SecondLightState();

    static SecondLightState* Instance();

    // 3秒経過したら次の状態に遷移する
    void PassTime( LightContext* context, time_t timePassed );

    // 黄と表示する
    void PrintColor();
};

3つ目の電灯の状態

class ThirdLightState : public LightState {
private:
    time_t m_timePassed;

    static ThirdLightState* instance;

    ThirdLightState();
public:
    ~ThirdLightState();

    static ThirdLightState* Instance();

    // 何もしない
    void PassTime( LightContext* context, time_t timePassed );

    // 青と表示する
    void PrintColor();

3つの状態をとる電灯

class TriStateLightContext : public LightContext {
private:
    LightState* m_state;

public:
    TriStateLightContext();
    ~TriStateLightContext();

    // 状態を指定された状態へ遷移させる
    LightState* ChangeState( LightState* nextState );

    // 時間を経過させる
    void PassTime( time_t timePassed );

    // 現在の状態の色を表示する
    void PrintColor();
};

2つの状態をとる電灯

class TwoStateLightContext : public LightContext {
private:
    LightState* m_state;

public:
    TwoStateLightContext();
    ~TwoStateLightContext();

    // 状態を指定された状態のうちSecondLightState以外は指定された状態へ
    // SecondLightStateの場合はThirdLightStateへ遷移させる
    LightState* ChangeState( LightState* nextState );

    // 時間を経過させる
    void PassTime( time_t timePassed );

    // 現在の状態の色を表示する
    void PrintColor();
};


ここでは電灯の状態として3つの状態があるが、
電灯によっては2状態のみ取りうるものと、3状態取りうるものとを
別々のクラスとして実装している。


場合によっては、例外的にあるクラスでのみ
状態遷移シーケンスを変化させたい場合などがあり、
そのための条件をStateに含めずにContext側に持たせるようなケースが考えられる。
(あまり状態を増やしすぎると状態数が爆発するのでトレードオフ


このような場合、Contextをインターフェイスにして実装を変化させることで
例外的な状態遷移を行うことができる。
ただし、TwoStateLightContextクラスはSecondLightStateクラスや
ThirdLightStateクラスのことを知らなければいけなくなってしまう。


この辺はもう少しうまい例がありそうな気がするが、
今はちょっと思い浮かばない orz