39 Stimmen

Rückruf/Befehl vs. EreignisListener/Beobachter-Muster

Ich versuche, einen asynchronen Rahmen zu entwerfen und wollte wissen, was die Leute denken, sind die Vor- und Nachteile der Callback-Muster vs die Beobachter-Muster.

Callback pattern:

//example callback
public interface Callback{
    public void notify(MethodResult result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback callback){
     //do work
     callback.notify(result);
  }
}

//example observer pattern
public interface EventListener{
   public void notify(MethodResult result);

}

public class Worker{
  private EventListener listener;
  public registerEventListener(EventListener listener){
   this.listener=listener;
  }
  public void doAsyncWork(){
     //do work
     listener.notify(result);
  }
}

Ich arbeite mit einem Framework, das beide Muster zu verwenden scheint. Das EventListener-Muster ist nicht das typische Muster, da es keine Liste von Listenern hat. Dies kann jedoch leicht implementiert werden, indem man einen CompositeListener erstellt, der seine eigene Semantik bezüglich der Priorität der Listener hat und wie die Verteilung von Ereignissen an jeden Listener gehandhabt werden soll, z.B. durch das Erzeugen eines neuen Threads für jeden Listener im Vergleich zu seriellen Benachrichtigungen. (Ich denke eigentlich, dass dies eine gute Idee ist, da es eine gute Trennung der Anliegen und ist eine Verbesserung auf die Standard-Beobachter/Listener-Muster).

Haben Sie eine Idee, wann Sie die beiden verwenden sollten?

Vielen Dank.

41voto

saintedlama Punkte 6649

Befehls-, Rückruf- und Beobachtermuster haben unterschiedliche Semantiken:

  • Rückruf - meldet einem einzelnen Aufrufer, dass ein Vorgang mit einem Ergebnis abgeschlossen wurde
  • Beobachter - benachrichtigt null bis n interessierte Parteien, dass ein Ereignis (z. B. ein abgeschlossener Vorgang) eingetreten ist
  • commande - kapselt einen Operationsaufruf in einem Objekt und macht ihn so über eine Leitung übertragbar oder persistierbar

In Ihrem Beispiel könnten Sie sowohl Callback- als auch Observer-Muster kombinieren, um eine größere API-Flexibilität zu erreichen:

  1. Verwenden Sie die Rückruf Muster, um Vorgänge auszulösen und den Aufrufer asynchron zu benachrichtigen, dass der ausgelöste Vorgang beendet wurde.
  2. Verwenden Sie die Veranstaltung/Beobachter Muster zu geben, um einige andere Komponenten (die pas Auslösen des Vorgangs) die Möglichkeit, benachrichtigt zu werden, wenn ein Vorgang abgeschlossen ist.

28voto

Mairbek Khadikov Punkte 7629

Beide Muster sind großartig, und welches man wählt, hängt davon ab, was man bauen will und wie das Gerüst verwendet werden soll.

Wenn Sie versuchen, eine Art von Publish-Subscribe-System mit folgendem typischen Arbeitsablauf aufzubauen:

  • Client startet asynchrone Aufgabe und vergisst sie
  • mehrere Handler erhalten Benachrichtigungen, wenn eine Aufgabe abgeschlossen ist

dann Observer Muster ist eine natürliche Wahl für Sie. Da es sich um ein Framework handelt, sollten Sie auch die Verwendung von EreignisBus Muster, um eine lose Kopplung zu erreichen.

Wenn Sie nicht mehr als eine einfache asynchrone Ausführung benötigen und ein typischer Ablauf mit Ihrem Framework ist:

  • Start asynchrone Aufgabe
  • etwas tun, wenn es abgeschlossen ist

o

  • Start asynchrone Aufgabe
  • etwas tun
  • warten, bis sie abgeschlossen ist, und dann etwas tun

dann sollten Sie sich für die einfache Callback .

Aber um eine brauchbarere und saubere API zu erreichen, empfehle ich Ihnen, die folgenden Elemente loszuwerden Callback Abstraktion und entwerfen Sie Ihren Arbeitscode so, dass er eine Art von Future .

public interface Worker<T> {

    Future<T> doAsync();

}

Et Worker kann auf folgende Weise verwendet werden:

Future<Integer> future = worker.doAsync();

// some work here

Integer result = future.get(); // waits till async work is done

Future könnte ein Standard sein java Zukunft . Aber ich würde vorschlagen, Sie verwenden ListenableFuture aus der Guava-Bibliothek.

5voto

Tom Punkte 41119

Ich würde argumentieren, dass das Callback-Muster besser ist, da es einfacher ist, was bedeutet, dass es vorhersehbarer und weniger wahrscheinlich ist, dass es aufgrund seines eigenen sich ändernden Zustands zu Fehlern kommt. Ein Beispiel dafür wäre in der Praxis die Art und Weise, wie GWT die Kommunikation zwischen Browser und Server handhabt .

Sie sollten allerdings Generika verwenden:

//example callback
public interface Callback<T> {
    public void notify(T result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback<SomeTypeOrOther> callback){
     //do work
     callback.notify(result);
  }
}

2voto

Christo Kumar Punkte 176

Betrachten wir das Beispiel von Lampe und Schalter, um den Unterschied zwischen Beobachter- und Befehlsmuster zu sehen.

Beobachter-Muster

  • Schalter ist ein Subjekt und eine Liste von Lampen sind Beobachter, auf denen ON/OFF Aktionen angewendet werden können.
  • Es ist eine Beziehung zwischen einem und vielen.
  • Die Aktionen EIN/AUS sind eigentlich Funktionen in ihrer einfachsten Form.
  • Bietet keine Kapselung der Befehle in ihrer einfachsten Form.

Befehlsmuster

  • Andererseits wird im Befehlsmuster Actions ON/OFF zu Command Klasse.

  • Die Klasse Command enthält den Empfänger Lamp, auf den eine Aktion angewendet werden kann.

  • Das Befehlsmuster ist oft eine Eins-zu-eins-Beziehung, kann aber skaliert werden, um auch eine Beziehung zwischen mehreren Personen herzustellen.

  • Das Befehlsmuster sorgt für die richtige Kapselung des Befehls.

0voto

Mohan Punkte 4179

Die Muster "Beobachter" und "Befehl" haben nur wenige gemeinsame Absichten und können kombiniert werden. Der Unterschied liegt jedoch in ihrer Motivation.

Beobachter-Muster beschreibt, wie man die Beziehung zwischen Thema y Beobachter . Sie konzentrierte sich nicht darauf, einen Befehl als separate Klasse zu erstellen und ihn zu parametrisieren, damit das Befehlsobjekt gespeichert werden kann und rückgängig zu machende Operationen unterstützt. Aber das ist es, was das Command-Muster tut.

Befehlsmuster beschreibt, wie man die Beziehung zwischen Aufrufer , commande et Empfänger . Es ging nicht darum, wie man eine beliebige Anzahl von Beobachtern unterstützen und verwalten kann. Aber das ist es, was das Observer-Muster tut.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X