Wie man Beobachtermuster in C ++ implementiert [geschlossen]

9

Ich habe eine Animationsklasse. Ich brauche einige Beobachter für die Ereignisse Play , Pause und Stop in der Animation. Ich habe 2 Lösungen für dieses Problem gefunden, aber ich weiß nicht, was ich wählen soll.

  1. Verwenden Sie boost :: Signale oder ähnliches und registrieren Sie Rückrufe für jedes Ereignis

  2. Erstellen Sie eine einfache Schnittstelle mit 3 rein virtuellen Funktionen ( OnPlay() , OnPause() , OnStop() ) und übergeben Sie diese an die Animationsklassenobjekte, die diese Schnittstelle implementieren.

Für jede Methode gibt es Vor- und Nachteile. Ich werde versuchen, diejenigen aufzuzählen, die ich bisher gefunden habe:

Vorteile für 1.

  • Ich kann jede Mitgliedsfunktion / freie Funktion als Rückruf verwenden
  • Ich muss nicht alle 3 Funktionen implementieren, wenn mir nicht alle wichtig sind
  • Dasselbe Objekt kann als Beobachter für mehrere Animationen verwendet werden, ohne zusätzliche Parameter aus der Animationsklasse
  • zu übergeben

Nachteile für 1.

  • Ich muss für jeden Callback ein Callable Objekt erstellen
  • Wenn ich später ein neues Ereignis hinzufügen möchte, wird es schwer sein, die Orte zu finden, an denen es verwendet wurde (der Compiler kann mich nicht dazu zwingen, ein neues Ereignis zu implementieren oder zu ignorieren).
  • Irgendwie seltsame Syntax (ich muss std :: bind / boost :: bind überall verwenden).

Vorteile für 2.

  • Leicht verständliche Konstruktion
  • Wenn ich ein neues Event in der Interface-Klasse "Animation / Observer" hinzufüge, wird der Compiler mich zwingen, die neue Funktion zu implementieren (zu leeren).

Nachteile für 2.

  • Ich muss 3 Funktionen implementieren (leer), auch wenn ich nur ein
  • benutze
  • Das gleiche Objekt kann nicht als Beobachter für verschiedene Animationen verwendet werden, ohne einige zusätzliche Parameter aus der Animation (ID oder etwas) zu senden.
  • Freie Funktionen können nicht verwendet werden.

Können Sie mir bitte sagen, was ich benutzen soll? Aus Ihrer Erfahrung, was ist besser für dieses Problem - die Freiheit von der ersten Approach oder klar und leicht zu verstehen Code aus der zweiten? Können Sie mir bitte andere Vorteile / Nachteile für beide Methoden oder andere Lösung geben?

    
Felics 29.07.2013, 12:46
quelle

3 Antworten

3

Zunächst wäre es nützlich zu wissen, ob die "Bindung" zur Kompilierungszeit bekannt ist oder nicht. Wenn das der Fall ist, würde ich vorschlagen, dass Sie sich die Richtlinienklassen ansehen.

Abgesehen davon würde ich für eine Mischung der zwei Lösungen gehen, d. h. den Schnittstellenansatz verwenden und eine Schnittstelle implementieren, die als ein Relayer für Signale / Frei-Funktionen dient. Auf diese Weise können Sie Standardverhalten haben, Sie können benutzerdefinierte Objekte hinzufügen, die die gesamte Schnittstelle implementieren, und haben im Grunde die Vorteile der beiden Ansätze sowie viel Flexibilität.

Hier ist ein grundlegendes Beispiel für den vorgeschlagenen Ansatz, ich hoffe, es ist hilfreich.

%Vor%

Hier können Sie ausprobieren. Dieses Beispiel verwendet insbesondere eine Richtlinienklasse (daher ist keine Schnittstelle "formal" definiert und Sie können die Schnittstelle "anreichern", wie es mit setPlayHandle gemacht wurde). Sie können jedoch auch etwas ähnliches mit der Laufzeitbindung tun.

    
Stefano Falasca 29.07.2013 12:54
quelle
1

Für alle bis auf die einfachsten Beispiele für Spielzeug Boost.Signals2 wäre meiner Meinung nach die bessere Lösung. Es ist gut gestaltet, gut getestet und gut dokumentiert. Das Rad neu zu erfinden ist gut für die Hausübung, aber nicht für den Produktionscode. Z.B. Deinen eigenen Beobachter threadsicher zu machen, ist nicht trivial, um richtig und effizient zu werden.

Erörterung Ihrer aufgeführten Nachteile

  • Sie können C ++ 11 lambdas anstelle von benannten Funktionsobjekten schreiben oder boost::bind syntax verwenden (was sowieso nicht kompliziert ist)
  • Ich verstehe Ihre Aussage über ungenutzte Ereignisse nicht ganz. Sie können ziemlich fortgeschrittene Verbindungsverwaltung durchführen, um Signale abzufragen und zu trennen aus den Slots.

TL; DR : Machen Sie sich mit Boost.Signals2

vertraut     
TemplateRex 29.07.2013 14:29
quelle
0

Ich denke, Sie können beide verwenden, aber es hängt von den Bedürfnissen ab. Ich habe einen Code, wo ich diese beiden Muster verwende. Es gibt viele Funktionen namens onSomething () (onMouseButton (), onKey (), onDragStart () usw.), aber es gibt auch Callbacks. Wenn ich etwas Verhalten implementieren muss, aber für die gesamte Klasse von Objekten, verwende ich onSomething () -Ansatz. Aber wenn ich ein paar Objekte der gleichen Klasse habe, aber nur ein Teil von ihnen eine erweiterte Funktionalität benötigt, ist Callback der perfekte Weg.

In der Implementierung wird es so gemacht: Es gibt einen Dispatch-Code, der versucht, die onSomething () -Methode zu verwenden (die bool zurückgibt), wenn das Ergebnis falsch ist - dann wird überprüft, ob ein Callback definiert ist, wenn ja, wird er ausgeführt.

    
baderman 29.07.2013 12:59
quelle

Tags und Links