1

この問題について話すほど、理解が深まるようです。私の前の質問は、私が正しくやろうとしていることを伝えていなかったと思います。申し訳ありません。

私のデザインには、本質的に集約クラスであるGameObjectがあり、GameObjectのすべての機能は、さまざまな「機能」を追加することによって実装されます。機能は、独自のメンバーと関数を持つ機能クラスのサブクラスです。すべての機能がメッセージを受信できます

class Feature
    {
    public:
        virtual void takeMessage(Message& message) = 0;
    };

class VisualFeature : public Feature
    {
    public:
        void takeMessage(Message& message);
    private:
        RenderContext m_renderer;
    };

... Additional Features ...

FeatureServerは、さまざまな機能の調整を担当するオブジェクトです。GameObjectsはFeatureServersにサブスクライブしてメッセージを受信でき、FeaturesはGameObjectsにサブスクライブして関心のあるメッセージを処理できます。

したがって、たとえばこのコードでは:

GameObject Square;
VisualFeature* SquareSprite = new VisualFeature();
Square.subscribe(SquareSprite, "MESSAGE_RENDER");
Square.addFeature(SquareSprite);
m_VisualFeatureServer.subscribe(Square, "MESSAGE_RENDER");

VisualFeatureServerは、「MESSAGE_RENDER」に関連付けられたメッセージを送信します。これは次のようになります。

class Message
    {
    public:
        std::string getID() {return m_id;}
        bool isConsumed() {return m_consumed;}
        void consume() {m_consumed = true;}
    protected:
        bool isConsumed;
        std::string m_id;
    }

class Message_Render : public Message
    {
    public:
        Message_Render() : m_id("MESSAGE_RENDER"), m_consumed(false) {}
        RenderTarget& getRenderTarget() {return m_target;}
    private:
        RenderTarget& m_target;
    };

VisualFeatureServerがMessage_RenderクラスをSquareGameObjectに送信すると、その特定のメッセージを受信するようにサブスクライブされている任意のFeatureComponentsに転送されます。この場合、VisualFeatureクラスはMessage_Renderメッセージを受信します。ここで私の問題があります。VisualFeatureクラスはMessage&を受信し、そのIDによってMessage_Renderであることがわかります。これを、次のようなメッセージではなく、Message_Renderとして処理できるようにします。

void VisualFeature::takeMessage(Message& message)
    {
    //Here's the problem, I need a pattern to handle this elegantly
    derivedMessage = convertMessageToDerivedType(message);
    this->handleDerivedMessageType(derivedMessage);
    }

void VisualFeature::handleDerivedMessageType(Message_Render& message)
    {
    message.getRenderTarget().render(m_renderer);
    message.consume();
    }

このデザインのtakeMessage部分をエレガントに処理する方法はありますか?

4

4 に答える 4

1

もう1つの答えは、編集で肥大化しすぎたため、新しいものを開始しました。

関数で行っているキャストreceiveMessage()は間違いなくコードの臭いです。

次の組み合わせを使用する必要があると思います。

各コンポーネントタイプは、それ自体のタイプのメッセージのみをサブスクライブするため、そのコンポーネントを対象としたメッセージのみを受信するという考え方です。これにより、キャストの必要がなくなります。

通知オブジェクトは、例として、メッセージIDでインデックス付けされた通知オブジェクトのベクトルを使用できます。監視オブジェクト(派生コンポーネントクラス)は、独自のメッセージIDでインデックス付けされた特定の通知機能をサブスクライブできます。

このデザインパターンが役立つと思いますか?

于 2009-11-12T04:32:51.977 に答える
1

私はあなたの質問を本当に理解しているかどうかわかりません、そしてあなたはあなたがもっと達成しようとしていることを明確にする必要があると思います。

ただし、他にもいくつかコメントがあります。

ここで使用するのに最適なデザインパターンは、(実装したように)パブリック継承ではないと思います。パブリック継承の黄金律は、派生クラスが本当に基本クラスの「オブジェクト」である場合にのみ使用する必要があるというものです。

C ++で継承を使用する主な利点の1つは、ポリモーフィズムを実装することです。たとえば、オブジェクトへのポインターのリストがあり、Baseそれらのオブジェクトでメソッドを呼び出し、それらが適切な関連メソッドVisualComponentPhysicsComponentオブジェクトメソッドにディスパッチされます。

(あなたの言葉では)それらは「無関係なクラスインターフェース」を持っているので、ポリモーフィズムの利点は何も得られません。

MixinパターンBaseを実装するためにクラスから実際に継承しているようです。

またはクラスにクラスのコピーBase(名前を変更する必要があります)を含める場合は、構成の方が優れたアプローチかもしれません。VisualComponentPhysicsComponent

ただし、次の質問に基づいています。

Baseへの参照またはポインターしかない場合、VisualComponentまたはPhysicsComponentのインターフェイスを公開するために必要な設計オプションは何ですか?

GameObject(あなたがインスタンス化している)クラスはすでにmain()あなたのためにこれを行っていませんか?


編集:

さて、質問が編集されたので、私はよりよく理解したと思います。

ただし、すべてのコンポーネントをGameObjectに動的に格納し、それでも個々のインターフェイスを使用できるようにする方法が必要です。

この動作を確認できる唯一の簡単な方法は、各派生クラスでオーバーライドされ、クラス固有の動作を実装する virtualメソッドを作成することです。ポインタのコンテナを格納し、派生クラスにディスパッチされるメソッドを呼び出すだけで済みます。BaseGameObjectBasevirtual

また、クラスがpublic( )メソッドにのみアクセスできるようにRender()Move()および非仮想メソッドを作成することをお勧めします。は、パブリックインターフェイスをクリーンに保つのに役立ちます。privateGameObjectvirtual

これが役立つかどうかはわかりません。


編集2:

コメントでさらに議論した後、ファクトリパターンまたは抽象ファクトリパターンが必要なように聞こえます。

于 2009-11-12T01:57:29.980 に答える
0

boost.signalsを見てください

メッセージタイプごとにシグナルを定義し、機能がそれにスロット(レシーバー)を追加できるようにすることができます。これは、任意の名前のメンバー関数、または適切な署名の他の呼び出し可能なものです。

于 2009-11-12T06:49:54.477 に答える
0

ビジターパターン。あなたが何を求めているのか理解できれば。

本当にもっとコンテキストを知る必要がありますが!

于 2009-11-12T01:57:03.387 に答える