![]() |
Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Guten Abend zusammen! :)
Es gibt ein Thema mit dem ich mich in den Jahren immer wieder intensiv auseinandersetzen musste und mit dem jeder von uns mehrfach täglich Kontakt hat und das wir glaube ich sehr intuitiv benutzen: Den Kontrollfluss von Ereignissen. :stupid: Stellt euch ein einfädiges Programm vor. Ereignisse (z.B. onClick) sind zentraler Bestandteil der Programmarchitektur. Insbesondere wird in der gewählten Architektur ein Ereignissystem eingesetzt, das bei einem einzelnen Ereignis mehrere Listener informieren kann (also zum Beispiel ein einzelnes "onClick" dazu, dass mehrere Programmroutinen nacheinander ausgeführt werden). [Edit] Nachdem "Der schöne Günther" mir bereits Feedback gegeben hat: Seine Zusammenfassung trifft mein Anliegen sehr gut; wer lieber meine Frage kurz und knapp lesen möchte, den verweise ich gerne einen Post weiter. Wenns um Details geht, bitte hier weiterlesen. [/Edit] Jetzt die Frage: Wie soll der Kontrollfluss eurer Meinung nach laufen? Also vorweggenommen: Beide hier vorgestellten Kontrollflussszenarien habe ich so in etwa schon gesehen und haben jeweils ihre Vor- und Nachteile. Ich glaube, dass man mit beiden Kontrollflussmechanismen in der Lage ist, die selben Programme zu schreiben. Es ist nur eine Frage der "Schönheit" :P Hier jetzt mal ein Beispielablauf (nur ganz grob):
Ab hier unterscheiden sich jetzt die beiden Ereignisarchitekturen. Kontrollflussbeschreibung "MachsSpäter" (defer):
Kontrollflussbeschreibung "MachsSofort" (immediate):[*]Das Ereignissystem betritt die Ereignisverteilungsroutine des "change"-Ereignisses[*]Die Listener des "change"-Ereignisses werden der Reihe nach abgearbeitet (und dabei können weitere synthetische Ereignisse ausgelöst werden, die dann wiederrum direkt abgearbeitet werden)[*]Der letzte Listener des "change"-Ereignisses wurde abgearbeitet.[*]Die verbliebenen Listener des "click"-Ereignisses werden abgearbeitet. Ereignisbehandlung analog.[*]Der letzte Listener des "click"-Ereignissses wurde abgearbeitet; es ist nichts mehr zu tun.[/LIST] Ab hier treffen sich beide Möglichkeiten wieder:
Folgende Eigenschaften sind zu beobachten:
Dadurch ergeben sich bei beiden Strukturen verschiedene Vor- und Nachteile durch die Reihenfolge der Abarbeitung. Zum Beispiel gibt es auch parametrisierte Ereignisse, deren Parameter vielleicht irgendwo den Zustand im Programm ändern. Klar, man kann sich als Programmierer auf beides einstellen; aber was gefällt euch mehr? Was findet ihr intuitiver? Seht ihr absolute Totschlagargumente, die absolut gegen die eine Architektur sprechen und für die andere? Habt ihr eine dritte Lösung, die komplett anders aussieht, aber ähnliche Architektur Anforderungen (mehrfache Listener an einem Ereignis, Single Threaded, usw) erfüllen? :-D Gruß, Brighty P.S. Ich habe gerade gesehen, dass die Listenabschnitte immer mit "1." anfangen. Der Forensoftware ist mein LIST=5 (bzw. LIST=10) scheinbar nicht Hinweis genug, dass die Liste da mit "5." (bzw. "10.") beginnen soll. Ihr müsst euch die Zahlen entsprechend vorstellen. |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Vielleicht liegt es an der Uhrzeit, aber ich musste mehr als einmal lesen um es zu verstehen. Eine kleine Skizze vom Ablauf*hätte (mir zumindest) geholfen ;-)
In einem Satz zusammengefasst: An einem OnClick-Event hängen mehrere Handler. Einer dieser Handler ändert z.B. eine Eigenschaft was wiederum ein OnChange-Event auslöst. Sollte man nun
Richtig verstanden? Vielleicht habe ich einfach noch nicht genug von der Welt gesehen, aber den "defer"-Ansatz habe ich weder irgendwo einmal gesehen, noch finde ich das in irgendeiner Weise intuitiv. Bei einem "Mach sofort"-Ansatz*könnte ich Events*deaktivieren, etwas tun und danach wieder aktivieren. Mit dem "defer"-Ansatz verliere ich das doch, oder? Ganz zu schweigen von dem Mehraufwand. Was z.B. wenn ich einen Handler entferne, der aber noch in irgendeiner "Mache später"-Queue steckt? Schwierig. Mir fehlt ein konkretes Beispiel wo der "defer"-Ansatz irgendeinen Vorteil hat. Was hierdurch einfacher wird.* Außerdem sehe ich nicht was an einem Event so "besonders" ist dass man es aufstauen sollte. Warum wird ein Handler der ein internes Feld ändert sofort ausgeführt, ein anderer der z.B. auf eine Property geht (deren Setter ein Event auslöst) aber später? Bzw. der Setter würde ausgeführt, nur der Code hinter dem Event nicht? Jeder*Code der hinter dem bewussten Ausführen eines Events steht müsste fortan davon ausgehen müssen, dass die*Folgen noch nicht eingetreten sind. Ziemlich verwirrend. Vielleicht aber auch nur für mich. PS: Mich haben deine "Beginnt mit"-Dinger verwirrt, vor allem da du erst ganz unten erklärst was du damit meintest. Lass die*Auflistung doch wie sie ist, das versteht denke ich trotzdem jeder. |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Zitat:
Zitat:
Zitat:
![]() In Javascript sieht man manchmal Codefragmente
Code:
, die auch diesen Zweck des Verzögerns erfüllen. Aber genau diese Behelfsstellen haben mich dazu angeregt näher darüber nachzudenken und meinen Code mancherorts zu überdenken.
setTimeout(function() { ... }, 0);
Das gruslige zur Intuition: Je länger ich mich damit beschäftige, desto interessanter finde ich eben auch diesen anderen Kontrollfluss. Zitat:
Zitat:
Thema Handler entfernen: Ja, wenn man Handler entfernt und hinzufügt während der Eventbehandlung ist so ein Sonderfall den man bei beiden Implementierungen genau betrachten muss: Man will im Optimalfall das gerade laufende Ereignis allen Listenern zustellen, die zum Triggerzeitpunkt des Ereignisses registriert waren. "defer" im Speziellen bildet sowas wie einen "ripple"-Effekt. Ein (zugegeben sehr synthetisches) Beispiel: zwei Listener auf ein und dem selben Event ändern je eine Eigenschaft von einem Rechteck. ListenerWidth ändert die Breite des Rechtecks und triggert ein weiteres Event zur Berechnung des Flächeninhalts. ListenerHeight ändert die Höhe des Rechtecks und triggert auch das Flächeninhaltsereignis. Bei "defer" ändern sich die Dimensionen des Rechtecks zuerst und dann wird zwei Mal der selbe Flächeninhalt berechnet (wobei wenn die Flächeninhaltsberechnung weitere Ereignisse auslöst, sie das durch ein identisches, bei der ersten Berechnung gecachtes Ergebnis beim zweiten Mal gar nicht auslösen muss!), bei "immediate" werden die Ereignisse in anderer semantischer Reihenfolge aufgelöst (es wird dazwischen einmal ein Flächeninhalt berechnet, der vermutlich nicht wichtig ist). Bei "defer" könnte man so zum Beispiel die Dimensionen ändern; ohne, dass der Flächeninhalt sich zwischendurch kurz "flackernd" auf einen Zwischenwert ändert (Beispiel: 3x6 wird zu 2x9 und der Flächeninhalt bleibt 18) Zitat:
Zitat:
Zitat:
|
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Hallo,
also, welcher der Ansätze implementiert wird, entscheidet doch der Programmierer, oder nicht? Beide Ansätze haben Nachteile. Vorteil des "Mache es sofort" ist ja der, dass das die VCL direkt "unterstützt", wenn man nicht gerade mit Threads arbeitet. Bsp: Listener 1 hängt am Edit1.OnChange Listener 2 hängt am Edit2.OnChange Listener 3 hängt am Edit3.OnChange Edit1.Text := 'bla' -> Edit1.OnChange -> Listener 1 wird informiert -> Listener1 setzt Edit2.Text -> Edit2.OnChange -> Listener 2 wird informiert jetzt geht es mit Edit1.OnChange und Listener 3 weiter Probleme könnte es geben, wenn z.B. Listener 3 auch wieder was an Edit1 macht |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Zitat:
Das "Sparen" von unnötigen Berechnungen am Beispiel deines Rechtecks kann ich auch nicht ganz nachvollziehen: Erstens fällt der Ansatz hier schon auf die Nase wenn der
Delphi-Quellcode:
beispielsweise nicht einfach stumpf +10 auf die Höhe gibt, sondern die Höhe nur ändert wenn z.B. der Flächeninhalt z.B. kleiner ist als X. Er bekommt jetzt einen falschen Flächeninhalt.
ListenerHeight
Das "Sparen" von unnötigen Berechnungen in dem Beispiel ließe sich einfacher und offensichtlicher lösen indem beim Ändern von Width und Height der berechnete Flächeninhalt entfernt wird ("invalidiert") und erst wieder ("lazy") berechnet wird wenn die Flächeninhalt-Property abgefragt wird. Nur so als Beispiel. Ich bleibe dabei: Gegen "Mach später" allgemein kann man nichts einwenden. Aber speziell an Events diese Philosophie "aufzuzwingen" wäre krass gegen meine Erwartungshaltung. |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Zitat:
Brighty |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Ich verstehe Dein Anliegen nicht so richtig.
Im Regelfall sollte ein Ereignis m.E. unmittelbar behandelt werden. Die Reihenfolge und Anzahl resultierender Behandlungen kann ggf. variieren und sollte i.d.R. keine schädlichen Auswirkungen haben. Wenn es doch mal zu irgendwelchen Seiteneffekten kommt muss man diese entsprechend explizit berücksichtigen (durch Einsatz von Flags o.ä.). Sofern man die Geschäftslogik und die GUI ordentlich voneinander trennt, hat man solche Probleme womöglich gar nicht. Bei der Delphi-Architektur verlangt das natürlich schon eine gewisse Selbstdisziplin. Vielleicht bin ich aber auch auf dem völlig falschen Gleis und habe die Fragestellung überhaupt nicht verstanden... |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Zitat:
Zitat:
Zitat:
Ich gebe zu, dass das alles ein wenig künstlich wirkt, aber ich bin auf der Suche nach einem möglichst schönen Paradigma was Ereignisse angehen. Brighty |
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Das erinnert mich an SendMessage und PostMessage. Was wäre bei diesen die bessere Variante. Antwort: je nach Anwendungsfall ;-)
|
AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Zu dem Schluss komme ich auch.
Als Paradigma würde ich vielleicht formulieren: Abhängigkeiten zwischen Modulen und Ereignissen nach Möglichkeit vermeiden. Wo das nicht möglich ist, Einzelfall-Lösungen finden, die mit den Abhängigkeiten umgehen können (und die können ganz unterschiedlich ausfallen). |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:20 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz