Frage

Je mehr ich über dieses Problem spreche, desto besser verstehe ich es. Ich denke, meine vorherige Frage hat nicht vermittelt, was ich richtig versuche. Ich entschuldige mich dafür.

In meinem Design habe ich GameObjects, die im Wesentlichen eine Aggregationsklasse sind. Alle Funktionen in einem GameObject werden implementiert, indem verschiedene "Funktionen" hinzugefügt werden. Eine Funktion ist eine Unterklasse der Feature -Klasse mit eigenen Mitgliedern und Funktionen. Alle Funktionen können Nachrichten empfangen

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

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

... Additional Features ...

Funktionen sind Objekte, die für die Koordinierung der verschiedenen Funktionen verantwortlich sind. GameObjects können Funktionen abonnieren, um Nachrichten von ihnen zu empfangen, und Funktionen können GameObjects abonnieren, um die Nachrichten zu verarbeiten, an denen sie interessiert sind.

Also zum Beispiel in diesem Code:

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

Der VisualFeatureServer sendet die Nachricht, die mit "message_render" gebunden ist, die möglicherweise so aussehen kann

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;
    };

Wenn der VisualFeatureServer die Message_Render -Klasse an das Square GameObject sendet, leitet sie sie an alle Featurecomponenten weiter, die abonniert sind, um diese bestimmte Nachricht zu erhalten. In diesem Fall empfängt die VisualFeature -Klasse die Nachricht von Message_Render. Hier ist mein Problem, die VisualFeature -Klasse wird eine Nachricht erhalten und dass sie feststellen kann, dass es sich um einen Message_Render von seiner ID handelt. Ich möchte sie in der Lage sein, sie eher als message_render zu behandeln, dann eher eine Nachricht wie SO:

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();
    }

Gibt es eine Möglichkeit, sich elegant mit dem Takemessage -Teil dieses Designs zu befassen?

War es hilfreich?

Lösung

Die andere Antwort war zu aufbläht mit Bearbeitungen, also habe ich eine neue gestartet.

Das Casting, das Sie in der machen receiveMessage() Funktionen sind definitiv ein Codegeruch.

Ich denke, Sie müssen eine Kombination aus verwenden:

Die Idee ist, dass jeder Komponententyp nur Nachrichten seines eigenen Typs abonniert und daher nur Nachrichten empfängt, die dafür bestimmt sind. Dies sollte die Notwendigkeit des Gießens beseitigen.

Das Benachrichtigungsobjekt könnte als Beispiel einen Vektor von Notifierobjekten verwenden, die von der Nachrichten -ID indiziert sind. Das Beobachtungsobjekt (die abgeleitete Komponentenklasse) könnte den jeweiligen Notifier abonnieren, der durch seine eigene Nachrichten -ID indiziert ist.

Denken Sie, dass dieses Designmuster helfen würde?

Andere Tipps

Ich bin mir nicht sicher, ob ich Ihre Frage wirklich verstehe, und ich denke, Sie müssen klarstellen, was Sie versuchen, mehr zu erreichen.

Nur ein paar andere Kommentare.

Ich denke nicht, dass die öffentliche Erbschaft (wie Sie implementiert haben) das beste Designmuster hier ist. Die goldene Regel mit öffentlichem Erbe ist, dass sie nur verwendet werden sollte, wenn die abgeleitet Klasse wirklich "ist ein" Objekt der Base Klasse.

Einer der Hauptvorteile der Verwendung der Vererbung in C ++ ist die Implementierung Polymorphismus wo (zum Beispiel) Sie eine Liste von Zeigern haben Base Objekte und Sie rufen Methoden auf diese Objekte auf, und sie werden in die Relevanten entsandt VisualComponent und PhysicsComponent Objektmethoden gegebenenfalls.

Da (in Ihren Worten) sie "nicht verwandte Klassenschnittstellen" haben, werden Sie keinen der Vorteile des Polymorphismus erhalten.

Es hört sich so an, als würden Sie wirklich von der erben Base Klasse, um die implementieren Mischen Muster.

Vielleicht ist Komposition der bessere Ansatz, bei dem Sie eine Kopie des Base Klasse (die Sie umbenennen müssen) in der VisualComponent oder PhysicsComponent Klasse.

Basierend auf der folgenden Frage:

Wenn ich nur einen Referenz oder einen Zeiger habe, um zu basieren, welche Designoptionen muss ich die Schnittstelle von Visualcomponent oder PhysicsComponent freilegen?

Ist nicht das GameObject Klasse (in dem Sie instanziieren main()) Tun Sie das schon für Sie?


Bearbeiten:

Okay, ich denke, ich verstehe jetzt besser, dass die Frage bearbeitet wurde.

Aber ich brauche einen Weg, um alle Komponenten dynamisch im GameObject zu speichern, kann aber dennoch ihre individuellen Schnittstellen verwenden.

Der einzig einfache Weg, den ich sehen kann, ist das Erstellen von a virtual Methode in Base Dies wird in jeder abgeleiteten Klasse überschrieben und implementiert das klassenspezifische Verhalten. GameObject könnte einfach einen Behälter von speichern Base Zeiger und rufen die an virtual Methoden (en), die in die abgeleiteten Klassen versandt werden.

Ich würde auch empfehlen, machen Render(), Move() und alle nicht virtuellen Methoden private so, dass die GameObject Klasse kann nur auf die Öffentlichkeit zugreifen (virtual) Methoden. Das hilft, die öffentliche Schnittstelle sauber zu halten.

Ich bin mir nicht sicher, ob das hilft.


Bearbeiten 2:

Nach weiteren Diskussion in den Kommentaren klingt es nach dem Fabrikmuster oder der abstraktes Fabrikmuster ist was du brauchst.

Besuchermuster. Wenn ich verstehe, was Sie fragen.

Ich muss zwar wirklich mehr Kontext wissen!

Sich ansehen Boost.Signals

Sie können ein Signal für jeden Nachrichtentyp definieren und zulassen, dass Funktionen Slots (Empfänger) zu ihm hinzufügen. Dies kann ihre Mitgliederfunktionen eines beliebigen Namens oder andere aufrufbare Dinge einer ordnungsgemäßen Signatur sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top