Das Beobachtermuster unter Verwendung des Ziehmechanismus

10

Ich habe mich über die folgende Implementierung von gewundert

public void update(Observable obs, Object arg)

Während ich an alle meine Beobachter senden und mit notifyObserver()I aktualisieren und Verweise an thisden Beobachter weitergeben gettersmöchte, kann ich das aus dem Betreff verwenden, um die gewünschten Informationen abzurufen.

Wofür ist das argArgument für die Aktualisierungsmethode gedacht?

USer22999299
quelle
@RBT argist ein Parameter oder eine Gruppe von Parametern als zusätzliche Option
umlcat

Antworten:

11

Bei der Implementierung des Observer-Musters sind zwei Hauptansätze zu berücksichtigen: das Push-Modell und das Pull-Modell.

Im "Push" -Modell sendet das Subjekt (dh das Observable) dem Beobachter bei Benachrichtigung alle Daten, die es benötigt. Der Beobachter muss das Thema nicht nach Informationen abfragen. Im "Pull" -Modell benachrichtigt das Subjekt den Beobachter lediglich darüber, dass etwas passiert ist, und der Beobachter fragt das Subjekt anhand der Informationen ab, die es benötigt.

Lassen Sie uns die Vor- und Nachteile beider Ansätze diskutieren:

drücken

Der Hauptvorteil des "Push" -Modells ist die geringere Kopplung zwischen dem Beobachter und dem Subjekt. Der Beobachter muss nichts über das Thema wissen, um es abzufragen. Wenn es nötig wäre, müssten wir eine der folgenden Aktionen ausführen: A - Downcasting auf der Seite des Beobachters durchführen, um klassenspezifische getMethoden zu diesem Thema aufzurufen . Das ist schlecht. B- die ObservableSchnittstelle klassenspezifischer gestalten, spezifische getMethoden anbieten , wodurch die Beziehung zwischen Beobachter und Subjekt weniger allgemein und die Dinge kopupelter werden.

Durch die Implementierung des Push-Modells vermeiden wir all dies.

Der Nachteil ist jedoch die geringere Flexibilität: Das Subjekt weiß möglicherweise nicht immer genau, welche Informationen die Beobachter benötigen, um sie an sie zu senden. Dies bedeutet häufig spezifischere Beobachter-Schnittstellen, z. B. solche AgeObserver, die benachrichtigt werden, wenn das 'Alter' des Betreffs geändert wird, und HeightObserverdie heightbei Benachrichtigung den aktuellen Betreff des Betreffs erhalten.

Dies ist eine Option. Das andere ist das Subjekt, das eine ganze Reihe von Informationen sendet, die in einem InfoObjekt eingekapselt sind, und von den Beobachtern von dort abfragen lässt. Aber auch hier können wir nicht sicher sein, ob wir die richtigen Informationen senden. Entweder dies oder die Beobachter müssen spezifischere Beobachterschnittstellen implementieren, wodurch die Kopplung auf der Beobachterseite verstärkt wird.

ziehen

Ich habe bereits die Nachteile des Pull-Modells festgestellt. Die Beobachter müssten Dinge über das Thema wissen, um die richtigen Informationen abzufragen, was A- zu Downcasting (hässlich) oder B- günstig zu spezifischeren ObservableSchnittstellen führt, die spezifischere Zugriffsmethoden bieten. Bietet zum Beispiel AgeObservableeine getAge()Methode an.

Der Vorteil davon ist mehr Flexibilität. Jeder Beobachter kann selbst entscheiden, was abgefragt werden soll, ohne sich darauf verlassen zu müssen, dass das Subjekt die richtigen Informationen sendet.


Sie sollten die Strategie wählen, die für das jeweilige Projekt, an dem Sie arbeiten, besser ist.

In Wirklichkeit haben Sie immer spezifische Observerund ObservableSchnittstellen, so dass Sie ohnehin eine gewisse Kopplung zwischen den Seiten haben.

Wählen Sie also entweder "Ziehen" oder "Drücken", je nachdem, was am besten zu Ihnen passt.

Brauchen alle AgeObservernur agedas Thema? Implementieren Sie das Push-Modell. Weniger Kopplung und einfacher.

Benötigen alle HeightObserverunterschiedliche Informationen zum Thema - auch bekannt als muss man das Alter abfragen und ein anderes Objekt muss zusätzlich zur Größe das Gewicht abfragen? Implementieren Sie das Pull-Modell. Dies würde Sie zwingen, Accessoren (Getter) zur ObservableSchnittstelle hinzuzufügen (entweder dies oder das eigentliche Objekt als Parameter in seinem expliziten Typ zu übergeben, aber wenn Sie dies über die Schnittstelle tun, können Sie den Beobachtern den Zugriff auf Dinge verweigern, die nicht wichtig sind Sie). Diese Lösung erzeugt eine höhere Kopplung, ist jedoch flexibler.

Wählen Sie, was am besten zu Ihrer Situation passt.

Aviv Cohn
quelle
Vielen Dank für diese Erklärung. Um auf meine Frage zurückzukommen, wie Sie sagten, während Sie Pull verwenden, muss ich das Casting und die Verwendung der Getter herunterfahren, aber wofür spricht die Beobachter-Aktualisierungsmethode? - public void update (Observable obs, Object arg)?
USer22999299
Ich bin mir nicht sicher, aber ich denke, das Object argist für das "Push" -Modell gedacht, woarg ein "Informationsbündel" an den Beobachter gesendet wird.
Aviv Cohn
Ja, das habe ich auch gedacht, aber warum schicken wir dann die Obs? :) Wenn wir das Casting beenden, können wir einfach die Informationen abrufen, die wir benötigen.
USer22999299
1
Sprechen Sie über "Push" oder "Pull"? Die Idee bei "Push" ist, dass der Beobachter es nicht wissen muss über die Art des Subjekts . So vermeiden Sie Downcasting. Das Herunterwerfen ist meistens schlecht, da es eine engere Kopplung zwischen den beiden Seiten schafft - der Betrachter kennt jetzt den genauen Typ des Motivs, der den gesamten Zweck übertrifft. Was ist, wenn später eine neue Klasse die ObservableSchnittstelle implementiert ? Wenn Sie sich nicht auf den konkreten Typ des Subjekts verlassen, dh kein Downcasting durchführen, funktioniert der aktuelle Beobachtercode polymorph genauso gut mit dem neuen Subjekt.
Aviv Cohn
1
Wenn Ihr Beobachtercode auf Downcasting beruht, muss er sich mit jeder neuen Klasse ändern, die die Observable-Schnittstelle implementiert, wodurch der gesamte Zweck des Musters zunichte gemacht wird. Dies ist ein Beispiel dafür, warum "Programmieren auf eine Schnittstelle, keine konkrete Implementierung" eine gute Sache ist - Code, der gegen eine Schnittstelle arbeitet, funktioniert mit jeder neuen Klasse, die die Schnittstelle implementiert, unverändert. Wenn Sie sich auf die konkrete Implementierung verlassen - z. B. durch Downcasting - muss sich Ihr Code mit jeder neuen Observable-Klasse ändern. Den ganzen Zweck schlagen.
Aviv Cohn