Dies geschieht normalerweise mithilfe von Nachrichten. Sie können viele Details in anderen Fragen auf dieser Site finden, wie hier oder dort .
Um auf Ihr spezielles Beispiel zu antworten, müssen Sie eine kleine Message
Klasse definieren , die Ihre Objekte verarbeiten können, z.
struct Message
{
Message(const Objt& sender, const std::string& msg)
: m_sender(&sender)
, m_msg(msg) {}
const Obj* m_sender;
std::string m_msg;
};
void Obj::Process(const Message& msg)
{
for (int i=0; i<m_components.size(); ++i)
{
// let components do some stuff with msg
m_components[i].Process(msg);
}
}
Auf diese Weise "verschmutzen" Sie Ihre Obj
Klassenschnittstelle nicht mit komponentenbezogenen Methoden. Einige Komponenten können die Nachricht verarbeiten, andere ignorieren sie möglicherweise einfach.
Sie können beginnen, indem Sie diese Methode direkt von einem anderen Objekt aus aufrufen:
Message msg(obj1, "EmitForce(5.0,0.0,0.0)");
obj2.ProcessMessage(msg);
In diesem Fall obj2
wählt s Physics
die Nachricht aus und führt die erforderliche Verarbeitung durch. Wenn Sie fertig sind, wird es entweder:
- Senden Sie eine "SetPosition" -Nachricht an sich selbst, die von der
Position
Komponente ausgewählt wird.
- Oder greifen Sie direkt auf die
Position
Komponente zu, um Änderungen vorzunehmen (völlig falsch für ein reines komponentenbasiertes Design, da Sie nicht davon ausgehen können, dass jedes Objekt eine Position
Komponente hat, die Position
Komponente jedoch möglicherweise eine Anforderung von ist Physics
).
Es ist generell eine gute Idee , verzögern die eigentliche Verarbeitung der Nachricht an die nächste Komponente zu aktualisieren. Die sofortige Verarbeitung kann das Senden von Nachrichten an andere Komponenten anderer Objekte bedeuten. Das Senden von nur einer Nachricht kann also schnell einen untrennbaren Spaghetti-Stapel bedeuten.
Sie müssen sich wahrscheinlich später für ein erweitertes System entscheiden: asynchrone Nachrichtenwarteschlangen, Senden von Nachrichten an Objektgruppen, Registrieren / Aufheben der Registrierung von Nachrichten pro Komponente usw.
Die Message
Klasse kann ein generischer Container für eine einfache Zeichenfolge sein, wie oben gezeigt, aber die Verarbeitung von Zeichenfolgen zur Laufzeit ist nicht wirklich effizient. Sie können einen Container mit generischen Werten verwenden: Zeichenfolgen, Ganzzahlen, Gleitkommazahlen ... Mit einem Namen oder noch besser einer ID, um verschiedene Arten von Nachrichten zu unterscheiden. Sie können auch eine Basisklasse ableiten, die bestimmten Anforderungen entspricht. In Ihrem Fall können Sie sich einen vorstellen EmitForceMessage
, der von Message
dem gewünschten Kraftvektor abgeleitet ist und diesen hinzufügt. Beachten Sie jedoch die Laufzeitkosten von RTTI, wenn Sie dies tun.