Ich habe zwei abstrakte Klassen Subject und Observer erstellt, die eine klassische Observer-Musterschnittstelle definieren. Ich leite von ihnen ab, um das Observer-Muster zu implementieren. Ein Beobachter könnte so aussehen:
void MyClass::Update(Subject *subject)
{
if(subject == myService_)
{
DoSomething();
}
else if(subject == myOtherService_)
{
DoSomethingElse();
}
}
Das ist in Ordnung und es sagt mir, wer etwas geändert hat. Es sagt mir jedoch nicht, was sich geändert hat. Manchmal ist dies in Ordnung, weil ich nur den Betreff nach den neuesten Daten abfragen werde, aber manchmal muss ich wissen, was sich genau am Betreff geändert hat. Ich stelle fest, dass sie in Java sowohl eine notifyObservers () -Methode als auch eine notifyObservers (Object arg) -Methode haben, um vermutlich Details darüber anzugeben, was sich geändert hat.
In meinem Fall muss ich wissen, ob eine von mehreren verschiedenen Aktionen zu diesem Thema stattgefunden hat, und, wenn es sich um eine bestimmte Aktion handelt, eine Ganzzahl kennen, die sich auf diese Aktion bezieht.
Meine Fragen sind also:
- Wie kann C ++ ein generisches Argument übergeben (wie Java)?
- Ist Observer überhaupt das beste Muster? Vielleicht eine Art Ereignissystem?
AKTUALISIEREN
Ich habe diesen Artikel gefunden, in dem es um das Templieren des Observer-Musters geht: Implementieren eines Subject / Observer-Musters mit Vorlagen . Ich fragte mich, ob Sie ein Argument vorlegen könnten.
Ich fand diese Stack - Überlauf Frage , die über Templating das Argument spricht: Template basierte Thema Beobachter - Muster - Sollte ich static_cast oder dynamic_cast . Das OP scheint jedoch ein Problem zu haben, das niemand beantwortet hat.
Das andere, was ich tun könnte, ist, die Update-Methode so zu ändern, dass ein EventArg-Objekt wie folgt verwendet wird:
void MyClass::Update(Subject *subject, EventArg arg)
{
...
Erstellen Sie dann Unterklassen des EventArg für bestimmte Argumentdaten, und setzen Sie sie dann vermutlich wieder in die bestimmte Unterklasse innerhalb der Aktualisierungsmethode um.
UPDATE 2
Es wurde auch ein Artikel zum Erstellen eines asynchronen nachrichtenbasierten c ++ - Frameworks gefunden. Teil 2, in dem erörtert wird, wie der Betreff Details darüber kommuniziert, was sich geändert hat.
Ich denke jetzt ernsthaft darüber nach, Boost.Signals zu verwenden . Die Verwendung meines eigenen Beobachtermusters machte Sinn, als es einfach war, aber die Vorlage des Typs und eines Arguments wird langsam kompliziert. Und ich brauche möglicherweise die Thread-Sicherheit von Boost.Signals2.
UPDATE 3
Ich habe auch einige interessante Artikel zum Beobachtermuster gefunden:
Generalizing Observer von Herb Sutter
Implementieren des Observer-Musters in C ++ - Teil 1
Erfahrungen mit der Implementierung des Observer Design Pattern (Teil 2)
Erfahrungen mit der Implementierung des Observer Design Pattern (Teil 3)
Ich habe meine Implementierung jedoch auf die Verwendung von Boost.Signals umgestellt, das zwar für meine Zwecke möglicherweise etwas aufgebläht ist, aber erfolgreich funktioniert. Und wahrscheinlich sind Bedenken hinsichtlich Aufblähung oder Geschwindigkeit irrelevant.
quelle
Antworten:
Ob C ++ oder JAVA, eine Benachrichtigung an den Beobachter kann zusammen mit den Informationen darüber erfolgen, was geändert wurde. Dieselben Methoden notifyObservers (Object arg) können auch in C ++ verwendet werden.
Im Allgemeinen bleibt das Problem bestehen, dass mehrere Probanden an einen oder mehrere Beobachter gesendet werden
class arg
können und daher nicht fest codiert werden können.Normalerweise ist es am besten, arg in Form von generischen Nachrichten / Token zu erstellen, die für verschiedene Klassen denselben Datentyp bilden, die Werte für verschiedene beobachtete Klassen jedoch unterschiedlich sind. Alternativ, wenn alle derartigen Benachrichtigungswerte aus der Klasse für eine Basisklasse abgeleitet werden, die allen gemeinsam ist.
Für Beobachter - Muster, es ist wichtig , dass Arg - Datentyp nicht schwer , zwischen dem Beobachteten und Beobachtern codiert - sonst ist es eine Kupplung , die Dinge schwierig zu entwickeln macht.
BEARBEITEN
Wenn Sie möchten, dass der Beobachter nicht nur beobachtet, sondern auch viele andere Aufgaben ausführen muss, basierend auf den Änderungen , können Sie auch das Besuchermuster überprüfen . Im Besuchermuster ruft der Beobachter / Besucher das geänderte Objekt auf und kann daher nicht nur wissen, was die Änderung ist, sondern tatsächlich daran arbeiten
quelle
Object
(void *
,boost::any
oder etwas ähnlich generisch) , als wenn Sie bestimmte Art passieren, denn mit dem speziellen Typ Sie bei der Kompilierung sehen werden , dass sich etwas verändert, während bei gattungs es wird kompiliert und funktioniert nicht mehr, da der Beobachter nicht mit den tatsächlich übergebenen Daten arbeiten kann.std::function
Boostboost::function
, Gtk +GClosure
, Python-gebundene Methoden usw.), also definiere ich einfach Methoden mit entsprechenden Signaturen und fordere das System auf, die tatsächlichen zu erstellen Beobachter. Die Kopplung ist zwar nur eine Möglichkeit, das Subjekt definiert die Schnittstelle für Beobachter, hat aber keine Ahnung von deren Umsetzung.Es gibt verschiedene Möglichkeiten, ein generisches Ereignisargument "Java Like" in C ++ zu senden.
1) Deklarieren Sie das Ereignisargument als ungültig * und wandeln Sie es im Ereignishandler in die richtige Klasse um.
2) Deklarieren Sie das Ereignisargument als Zeiger / Verweis auf eine neue Klasse / Schnittstelle wie (als Antwort auf Ihr Beispiel).
Und lassen Sie die tatsächlichen Ereignisargumentklassen von dieser Klasse ableiten.
Fragen zu einem vorlagenbasierten Beobachter
http://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ
quelle
Ich weiß nicht, ob dies der kanonische Name ist, aber seit meinen alten Smalltalk-Tagen erinnere ich mich an den Begriff "Aspekt", um zu identifizieren, was sich am Beobachtbaren geändert hat.
Es ist nicht so komplex wie Ihre Vorstellung von EventArg (und dessen Unterklasse). Es wird nur eine Zeichenfolge (kann sogar eine ganzzahlige Konstante sein) vom Beobachtbaren zum Beobachter übergeben.
Plus: Es gibt nur zwei einfache Methoden (
update(observable)
undupdateAspect(observable, aspect)
Minuspunkt: Der Beobachter muss den Beobachter möglicherweise um weitere Informationen bitten (dh Ihre "Ganzzahl").
quelle