2009-06-08 6 views
4

Geht man schnell durch das GoF und das Head-First-Design-Pattern-Buch, so scheint es, als ob es keine Erwähnung der Endlosschleife-Erkennung und -Behandlung für das Observer-Muster gibt.sollte das Observer Pattern eine Endlosschleife enthalten?

Ich denke, wenn es zwischen 2 Klassen ist, können wir vorsichtiger sein über die Endlosschleife Problem, aber was ist, wenn es 5 Klassen oder 12 Klassen gibt, und die Beobachter gehen Multi-Richtungen. Ist in diesem Fall keine Endlosschleife möglich und sollte diesem Muster eine Erkennung hinzugefügt werden?

+0

Arrr, Leiter der ersten Entwurfsmuster. Ganz oben in der Liste der Bücher mit den dümmsten Titelbildern. –

Antwort

10

Unendliche Schleifen können nur passieren, wenn (a) Beobachter auch beobachtbar sind, (b) Veränderungen, die sie beobachten, zu Veränderungen in sich führen können, (c) der Beobachtungsgraph zyklisch ist und (d) eine Art von Änderung vorliegt was zu einer gleichartigen Veränderung führen kann. Die ideale Lösung bestünde darin, das Risiko von Endlosschleifen auszugleichen, indem sichergestellt wird, dass eine dieser Anforderungen fehlt. Wenn Ihr aktuelles Design alle vier wahr macht, sehen Sie, ob Sie es ändern können, um einen von ihnen falsch zu machen.

Die traditionellen Verwendungen für Observer-Observable sind in geschichteten Architekturen - zum Beispiel, wo View-Controller Modellobjekte beobachten oder Event-Handler GUI-Komponenten beobachten - und hier ist das Diagramm nicht zyklisch, so dass kein Risiko besteht Endlosschleife.

Ich sollte wahrscheinlich über Punkt (d), über verschiedene Arten von Änderungen erklären. Was ich meine ist, dass, wenn Sie eine Situation haben, wo ein UserInputEvent ein ModelStateChangedEvent auslösen kann und ein ModelStateChangedEvent ein WidgetUpdateEvent auslösen kann, das selbst nichts auslösen kann, selbst wenn die Beobachter einen zyklischen Graphen bilden, können Sie niemals Erhalten Sie unendliche Schleifen, weil es nur eine endliche Anzahl von Stufen in der Abfolge von Ereignissen gibt. Effektiv bilden die Ereignisse einen azyklischen Graphen, selbst wenn die Beobachter dies nicht tun. Wenn jedoch ein ModelStateChangedEvent ein anderes ModelStateChangedEvent auslösen kann, besteht die Gefahr von Zyklen.

Wenn Sie wirklich nicht das Risiko von Zyklen vermeiden können, dann können Sie eine Idee aus Jon Postel stehlen, und jede Ereignisbenachrichtigung eine ganzzahlige Time-to-live-Zähler führen. Wenn ein Observable ein "originelles" Ereignis ausstrahlt, was etwas bedeutet, das von außerhalb des Beobachter-Netzwerks kommt und eine Kaskade von Ereignissen in ihm auslöst, setzt es den Zähler auf einen geeigneten anfänglichen TTL-Wert. Wenn ein Observable auf ein Ereignis reagiert, indem er ein anderes Ereignis ausstrahlt, würde es eine TTL weniger als die des auslösenden Ereignisses verwenden. Wenn ein Beobachter eine Benachrichtigung mit einer TTL von Null erhält, ignoriert er dies.Dies würde unendliche Schleifen verhindern, würde aber auch verhindern, dass ein Beobachter auf einige Ereignisse "richtig" reagiert, also ist es eine Idee, mit Vorsicht verwendet zu werden. Ich würde sehr empfehlen, dass eine Ereigniskaskade, die das TTL-Limit erreicht, als das Ergebnis eines Programmierfehlers betrachtet wird und auf die gleiche Weise protokolliert und gemeldet werden sollte, wie Sie mit einer NullPointerException oder einem Assertionsfehler umgehen.

1

Nein. Jede Situation, die eine Endlosschleife verursacht, ist offensichtlich ein Zeichen für ein schlechtes Design. Ich habe nie gesehen, dass dies zufällig im Beobachter passiert ist, und ich sehe keine Notwendigkeit, spezielle Fälle dafür in den Observablen zu schreiben.

Dies ist ein Fall von Do not Do That Than.

4

Unendlich Schleifenbehandlung könnte Teil der tatsächlichen Implementierung des Musters sein, aber die Beschreibung des Musters selbst sollte allgemein sein und sich nicht mit diesen Details befassen.

1

Ist die Endlosschleife im Allgemeinen äquivalent zu Turings Halteproblem? Wenn ja, dann könnte das nicht möglich sein.

+0

Ich glaube nicht, dass sie gleichwertig sind. Angenommen, Sie können eine ID für das ursprüngliche Ereignis generieren. Markieren Sie jedes Mal in einer globalen Tabelle, wenn ein bestimmter Beobachter ein Ereignis sieht. Wenn ein Beobachter ein Ereignis bereits gesehen hat, propagiert es es einfach nicht. Letztendlich werden alle Beobachter, die sich für eine Veranstaltung registriert haben, gesehen haben. Keines davon wird es wieder verbreiten, so dass es keine Endlosschleife geben könnte. Ich glaube nicht, dass ich gerade das Halteproblem gelöst habe, aber ich denke, dass es für dieses Problem funktionieren würde. – tvanfosson

+1

Es ist subtiler als das. Beobachter geben keine Änderungen an ihren Observablen weiter; Vielmehr kann eine beobachtete Änderung eine Änderung des Beobachters auslösen, die dann ausgestrahlt werden müsste. Wenn eine Änderung in A eine Änderung von B auslöst, ist die Änderung von B eine deutliche Änderung gegenüber der Änderung von A, und Sie können sie nicht einfach unter einer einzigen ID kombinieren und ignorieren. –

1

Wie @Matthew darauf hinweist, wäre dies ein Fall von schlechtem Design, und Sie sollten das während des Entwurfs erfassen und es lösen, indem Sie das Design verbessern und dem Code nicht mehr Komplexität hinzufügen. Insbesondere denke ich, dass es ein Zeichen dafür wäre, dass Klassen keinen Zusammenhalt haben, dass Verantwortlichkeiten auf die verschiedenen Klassen verteilt sind und nicht einer einzelnen Klasse oder einer kleinen Gruppe kooperierender Klassen zugewiesen werden. Richtig angewendet auf ein gutes architektonisches Design sollte das Observer-Muster keine spezielle Handhabung erfordern, um die unendliche Erzeugung von Rückrufen zu verhindern.

1

Es ist irgendwie komisch, dass Leute mit hoher Bewertung solch nutzlose Antworten geben. seufzer

Event-Schleifen passieren und passieren sehr oft in der GUI-Programmierung. Es scheint mir, dass mehr oder weniger Standardlösung darin besteht, die Schleifen zu unterbrechen, indem entweder doppelte oder redundante Ereignisse gefiltert werden oder eine Methode eingeführt wird, die keine Ereignisse auslöst.

Verwandte Themen