Event Handler : Methoden referenzieren oder direkt angeben



  • In Java und auch in C++ gibt es ja mittlerweile Syntax-Sugar wie Lamda aber auch Method-references.

    Wenn man jetzt für Desktop-Apps GUIs schreibt (und keinen Designer verwendet), dann gibt es ja oft irgendeine initGUI() Methode, die alle möglichen Elemente anlegt und positioniert.
    Also Textfelder, Buttons, Choice-Boxen, was auch immer.

    Da man hier die einzelnen GUI-Elemente erzeugt, fügt man ihnen an dieser Stelle oft auch oft ihre Event-Handler hinzu.
    In Java hat man jetzt z.B. die Wahl, ob man die Logik für das Handeln des Events direkt in dieser initGUI() Methode per Lamda/AIC angibt oder eben eine Methode referenziert. In C++ wird das wohl ähnlich sein.

    Ich frage mich da immer: Schreibe ich jetzt den Event-Handeling Code direkt mit in die initGUI()-Methode oder definiere ich kleine private Methoden, die ich an der Stelle nur referenziere.
    Mein Gefühl sagt mir, dass es übersichtlicher ist, die Methoden hier nur zu referenzierne.
    Damit hätte ich das von dem ganzen Layout-Kram getrennt und es wäre somit übersichtlicher.
    Man könnte jetzt aber auch argumentiere, dass die ganzen private Methoden eh nur an einer Stelle verwendet werden, sie also keinen Sinn machen.

    Wie seht Ihr das?



  • Wie so häufig, kommt drauf an.

    Bei größeren Gui Elementen, übergebe ich das als Referenz auf eine Memberfunktion. Im übrigen mache ich das ganze gerne auch im Konstruktor, oder lasse den Konstruktor die Init Methode aufrufen.

    Bei kleineren GUI Elementen, wähle ich gerne die Lambda Variante, weil ich direkt an einer Stelle sehe, was passiert und welches Element welche Funktion hat.

    Bei Elementen die nur Kontextabhängig erstellt werden, wähle ich meistens auch den Lambda Ansatz. Hängt aber auch immer davon ab, was alles gemacht werden soll. Wenn die Funktion etwas länger wird, dann doch besser als Referenz.



  • Ich benutze nichts von dem, sondern Command-Objekte. :p

    Aber am Ende ist es egal, weil natürlich muss man irgendwie "referenzieren". Wichtig ist nur, das der zu referenzierende Algorithmus nicht direkt im GUI-Code ist... außer es ist GUI-Logik.



  • Schlangenmensch schrieb:

    ...

    Das würde ich fast 1:1 so unterschreiben, wie sehen das also sehr ähnlich. Bei wirklich kleinen Handlern kann ich es, wie du schon geschrieben hast, durchaus verstehen, dass man das per Lamda direkt hinschreibt.
    Nur bei größeren stört es halt irgendwie den Lesefluss, imho.

    Artchi schrieb:

    Command-Objekte.

    Interessant, kannte ich jetzt zB noch gar nicht, musste ich mir erstmal anschauen.
    Sieht etwas komplexer aus, aber ich denke wenn man es ein paar mal verwendet hat, gewöhnt man sich dran.
    Wenn ich das jetzt richtig überflogen habe, dann wird ja mit dem Pattern auch der Handler-Code aus der Init Methode entfernt, also ähnlich bei beim Referenzieren.



  • Das Command-Pattern ist ja so ähnlich dem Functions-Object von C++. Du führst eine Aktion später aus, die auch noch einen Status speichern kann. Anstatt einer execute-Funktion im Objekt könnte man auch den ()-Operator in der C++-Klasse überladen (ist aber nur Syntax-Zucker).
    Die Command-Objekte kann man dann auch nach Ausführung z.B. in einer Liste speichern um daraus ein Undo-Pattern zu nutzen. Dazu könnte man in den Objekten eine Undo-Funktion implementieren, und anhand des vorhandenen Status (aus der execute-Funktion) später ein Undo ausführen.

    Ich könnte ohne Command-Pattern fast nicht mehr ruhig schlafen. 😉



  • Artchi schrieb:

    Ich könnte ohne Command-Pattern fast nicht mehr ruhig schlafen. 😉

    Tatsächlich so viel besser / schöner als Lamdas/Referenzen?
    Dann werde ich mir das auch noch mal genauer anschauen, vielleicht möchte ich ja auch das für die Zukunft verwenden



  • Hem, kommt sicherlich auf die Anforderungen an?

    Wenn ich einen Status brauche, wird das doch mit den Lambdas eher nicht gehen? Lambdas sind einfach nur anonyme Funktionen?

    Wenn mir eine Funktion reichen wird, kann ich ein Lambda schreiben. Aber falls nicht, brauche ich doch ein Functions-/Command-Object?
    Auch bei einem Undoable-Command komme ich mit einer Funktion/Lambda nicht weit, da müsste ich dann einen Workaround schreiben, den ich bei einem Undoable-Command Freihaus habe. Bei einem Command lege ich dieses nach dem Exucute einfach auf den Undo-Stack ab.

    Und wie löse ich konfigurierbare Events? Also sagen wir mal, der Benutzer muss Aktionen umbelegen bzw. frei belegen können? Wie mache ich das mit Lambdas?



  • Artchi schrieb:

    Hem, kommt sicherlich auf die Anforderungen an?

    Wenn ich einen Status brauche, wird das doch mit den Lambdas eher nicht gehen? Lambdas sind einfach nur anonyme Funktionen?

    Hm, zum einen kann man eine Referenz auf eine Funktion eines Objektes auch verwenden, ohne direkt das gesammte Command Pattern zu implementieren.
    Bei Lambdas könnte man den this Pointer Capturen und damit einen Zustand an das Lambda übergeben.

    Artchi schrieb:

    Wenn mir eine Funktion reichen wird, kann ich ein Lambda schreiben. Aber falls nicht, brauche ich doch ein Functions-/Command-Object?
    Auch bei einem Undoable-Command komme ich mit einer Funktion/Lambda nicht weit, da müsste ich dann einen Workaround schreiben, den ich bei einem Undoable-Command Freihaus habe. Bei einem Command lege ich dieses nach dem Exucute einfach auf den Undo-Stack ab.

    Auf jeden Fall ein guter Punkt für das Command Pattern. Undo/Redo bekomme ich da recht preiswert, um nicht zu sagen, Freihaus dazu.

    Artchi schrieb:

    Und wie löse ich konfigurierbare Events? Also sagen wir mal, der Benutzer muss Aktionen umbelegen bzw. frei belegen können? Wie mache ich das mit Lambdas?

    Beispielsweise könnte man die verschiedenen Aktionen in einer Map ablegen (via std::function). Und jenachdem welche Funktionalität gefordert wird, dann die entsprechende auswählen.

    Ist sicherlich immer eine Frage der konkreten Anwendung. Bei "kleinen" Aktionen, die z.B. schlicht ein neues Fenster öffnen, kann man sich meiner Meinung nach sparen, eine Klasse dafür zu schreiben. Wenn ich aber mehr erledigen möchte und Undo/Redo benötige, bietet sich das Command Pattern natürlich an.


Anmelden zum Antworten