ContextをInterfaceにする訳

http://d.hatena.ne.jp/fkm/20061125/p1

インターフェースにするとDoOkeyAction()の実装の部分で、インターフェースを実装してるクラスのフィールドとかメソッドとかを使って何かしたあとstate_->DoOkeyAction(this);とできる。

が正解。StateがState保持者であるContextに対して影響を与える必要がある場合、Contextのinterfaceを知っていないといけない。
SetState以外にもたとえば、

interface HogeContext {
    void 逃げる();
    void 攻撃();
    void SetState(HogeState s);
}

interface HogeState {
    void 攻撃された(HogeContext *c);
}

class 強気State : HogeState {
    void 攻撃された(HogeContext *c) {
        if (HPヤバイ) {
            s = new 弱気State();
            c->SetState(s);
            s->攻撃された(c);
        } else {
            c->攻撃();
        }
    }
}

class 弱気State : HogeState {
    void 攻撃された(HogeContext *c) {
        c->逃げる();
    }
}

となる。

だから、

thisで実装しているクラス(のインスタンス)のポインタが渡せるということは、危険な香りがするがdynamic_castで元に戻せる?

をしてはダメ。dynamic_castするんじゃなくて、Stateからアクセスできる関数はinterfaceで宣言しないと、Contextがinterfaceになっている理由がなくなっちゃう。


ちなみに、State保持者であるContextは一つだけである事が多いので、Stateクラスはコンストラクタで保持者であるContextへの参照をもらえば、毎回引数としてContextを受け取る必要はない。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。