Welche „Code-Gerüche“ sind ein Symptom dafür, dass ein Ereignis-Listener-Modell erforderlich ist?

10

Was sind die Symptome in einer Codebasis, die darauf hinweisen, dass ein Ereignis-Listener-Ansatz erforderlich ist?

Es scheint mir, dass wenn es Klassen gibt, die von mehreren aufgerufen werden müssen, die nicht zur Entwurfszeit anderer Klassen definiert sind, Sie eine Art Signalisierungsrahmen benötigen, aber ich würde gerne hören, welche anderen Situationen es gibt verbessert durch den Wechsel zu einem ereignisbasierten Modell.

Lurscher
quelle

Antworten:

8

Der Event / Listener-Ansatz versucht, eine enge Kopplung zu vermeiden , sodass alle Code-Gerüche, die darauf hinweisen, auf den Ansatz verweisen.

Basierend darauf würde ich die folgenden Symptome vorschlagen:

  • große Konstruktoren , da jedes Objekt jedes andere Objekt kennen muss und ohne es nicht funktionieren kann. Vielleicht so viele, die obj.set_dependecy(x)unmittelbar nach dem Konstruktoraufruf getarnt sind .

  • bidirektionale Abhängigkeiten , da der Informationsfluss ohne Ereignisse in einer imperativen Sprache im Grunde genommen "Push" ist (Aufruf einer Methode)

  • 'Hierarchie des Wissens' ist schwer zu bestimmen . Dies sind die bidirektionalen Abhängigkeiten , nur ein weiterer Schwerpunkt: Wenn es A gibt, das auf B hört, weiß A von B, aber B nicht von A, also gibt es eine 'Hierarchie': Einige Objekte wissen nichts, andere kennen andere usw. Wenn Sie beispielsweise MVC wie folgt implementieren: http://en.wikipedia.org/wiki/Model_View_Controller , kennt das Modell nur sich selbst, die Ansicht kennt das Modell und der Controller kennt Ansicht und Modell.

keppla
quelle
1
Bidirektionale Abhängigkeiten sind bei weitem das verräterischste Zeichen dafür, dass Sie zu einem ereignisgesteuerten Modell wechseln müssen. Das Aufblähen von Konstruktoren kann dies bedeuten, aber meistens bedeutet dies nicht nur, dass Sie mehr in Bezug auf Aggregation, Komposition und / oder allgemeine Abstraktion tun müssen (dh Refactoring, keine Designänderungen).
Aaronaught
Du hast recht. Ich habe versucht, es durch die einfache Erkennung zu ordnen, und große Konstruktoren sind so einfach, dass sie möglicherweise von regulären Ausdrücken erfasst werden.
Keppla
6

Wenn Sie nicht wissen können oder sollten, was auf eine Reihe von Nachrichten / Signalen / Ereignissen reagieren soll.

Oft ist es, wenn Sie möchten, dass "die Welt" etwas über etwas erfährt, das in einem Modul passiert (eine Klasse oder ein Klassensystem), aber Sie möchten sich nicht darum kümmern, was genannt wird.

Der damit verbundene Code-Geruch ist, um genau zu sein, wenn Sie das Gefühl haben, Code aus unabhängigen Modulen zu mischen, wobei eines etwas tut, auf das das andere reagieren sollte. Sobald Sie sehen, dass Sie abhängig vom Status / den Ereignissen von Modul A Code aus Modul B aufrufen müssen, benötigen Sie Ereignis-Listener.

Klaim
quelle
3

Ich würde Ihre Frage ändern und sagen: Wenn eine ereignisbasierte nicht die richtige Lösung für eine objektorientierte Anwendung ist? Ich denke, dass die meisten OO-Anwendungen davon profitieren können, wenn sie als Event-Produzenten und -Konsumenten konzipiert sind.

Am Ende ist ein "Methodenaufruf" tatsächlich eine Nachricht, die an einem Objekt ankommt, und das Objekt ist dafür verantwortlich, zu entscheiden, ob es etwas mit der Nachricht zu tun hat, und die Operation auszuführen. Dies ist in stark typisierten Sprachen wie Java nicht sehr klar, wird jedoch in dynamischen Sprachen wie Ruby deutlicher.

Ein weiterer interessanter Punkt beim Entwerfen einer Anwendung als ereignisbasiert ist, dass die internen Komponenten normalerweise ordnungsgemäß isoliert und kohärent sein müssen, da sonst der Code sehr, sehr schnell zu einem Chaos wird. Als Beispiel gefällt mir das von Alistair Cockburn verwendete Konzept der hexagonalen Architektur sehr gut , da dieses Muster normalerweise eine bessere Verkapselung erzeugt und (meiner Ansicht nach) kohäsivere Komponenten erzwingt.

Ich denke (aber ich liege wahrscheinlich falsch), dass dies auch mit dem Domain Driven Design-Konzept von Domain-Ereignissen zusammenhängt , bei dem die Domain-Klassen Ereignisse ausgeben, die von anderen Objekten erfasst werden, und diese Objekte noch andere Ereignisse ausgeben (Sie sehen, wo das geht: D). Was mir an diesem Muster gefällt, ist, dass Schnittstellen Rollen modellieren sollten, keine Implementierungen.

Es tut mir leid, wenn ich nicht viel Sinn mache. Ich habe in den letzten Monaten mit diesen Mustern experimentiert und dabei erstaunliche Ergebnisse erzielt, aber ich versuche immer noch, die Konzepte zu verstehen und zu verstehen, wie weit sie reichen.

Augusto
quelle
2

Überlegen Sie, was Sie tun müssten, wenn Event-Listener (auch bekannt als Observer Pattern) nicht vorhanden wären.

Wenn Sie ein Objekt haben, das Verweise auf eine Liste anderer Objekte enthält und zu einem bestimmten Zeitpunkt im Prozess eine Methode aufruft, sollten Sie dort definitiv ein Ereignis gehabt haben.

Wenn Sie ein Flag auf einem Objekt haben, das angibt, dass etwas getan wurde, und Sie dieses Flag von anderen Objekten aus beobachten, sollten Sie auf jeden Fall ein ereignisgesteuertes Modell verwenden.

Verwechseln Sie dies jedoch nicht mit einem Rückruf. Wenn Sie eine Methode für ein anderes Objekt aufrufen und eine Methode für das Ursprungsobjekt übergeben, zu dem Sie zu einem bestimmten Zeitpunkt zurückrufen möchten, sollten Sie dies so lassen, anstatt einen Ereignis-Listener zu verwenden.

pdr
quelle