2

最近、休止後にC ++開発に戻り、StateDesignPatternの実装について質問があります。GoFの本とまったく同じように、バニラパターンを使用しています。

私の問題は、ステートマシン自体が組み込みシステムの一部として使用されるハードウェアに基づいているため、設計が修正されて変更できないことです。これにより、2つの状態(特に)の間に循環依存が発生し、これを解決しようとしています。簡略化されたコードは次のとおりです(通常どおりヘッダーを使用してこれを解決しようとしましたが、それでも問題が発生しました。このコードスニペットではヘッダーを省略しています)。

#include <iostream>
#include <memory>

using namespace std;

class Context
{
public:
    friend class State;

    Context() { }

private:
    State* m_state;
};

class State
{
public:
    State() { }

    virtual void Trigger1() = 0;
    virtual void Trigger2() = 0;
};

class LLT : public State
{
public:
    LLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};


class ALL : public State
{       
public: 
    ALL() { }
    void Trigger1() { new LLT(); }
    void Trigger2() { new DH();  }
};  

// DL needs to 'know' about DH.
class DL  : public State
{           
public:
    DL() { }
    void Trigger1() { new ALL(); }
    void Trigger2() { new DH();  }
};      

class HLT :  public State
{
public:
    HLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};

class AHL : public State
{
public:
    AHL() { }
    void Trigger1() { new DH();  }
    void Trigger2() { new HLT(); }
};

// DH needs to 'know' about DL.
class DH  : public State
{
public:
    DH () { }
    void Trigger1() { new AHL(); }
    void Trigger2() { new DL();  }
};


int main()
{
    auto_ptr<LLT> llt (new LLT);
    auto_ptr<ALL> all (new ALL);
    auto_ptr<DL>  dl (new DL);
    auto_ptr<HLT> hlt (new HLT);
    auto_ptr<AHL> ahl (new AHL);
    auto_ptr<DH>  dh (new DH);  

    return 0;
}

問題は、基本的に、状態パターンでは、次の状態のコンストラクターを呼び出すContextクラスのChangeStateメソッドを呼び出すことによって状態遷移が行われることです。

循環依存のため、「問題」状態の両方のコンストラクターを事前に定義することができないため、コンストラクターを呼び出すことができません。

私はこの記事を見て、理想的な解決策のように思われたテンプレートメソッドを調べましたが、コンパイルされず、テンプレートに関する私の知識はかなり限られています...

私が持っていたもう1つのアイデアは、多重継承を介してヘルパークラスをサブクラス化された状態に導入し、基本クラスのコンストラクターを指定して、状態サブクラスのコンストラクターを参照できるかどうかを確認することです。しかし、それはかなり野心的だったと思います...

最後に、ファクトリメソッドデザインパターンを直接実装することが、問題全体を解決するための最良の方法でしょうか?

4

1 に答える 1

4

クラス定義の外部でメンバー関数を定義できます。たとえば、

class DL : public State
{
public:
    void Trigger2();
};

inline void DL::Trigger2() { new DH(); }

これらのクラスが定義された後、後のクラス定義に依存するメンバー関数を定義します。キーワードは、ヘッダーファイルのクラスの外部inlineでメンバー関数を定義する場合にのみ必要です。

余談ですが、なぜnew DH()関数で使用しているのですか。あなたはどこでもメモリリークしています!

于 2010-06-15T13:24:13.233 に答える