Ok, ich weiß, der Titel dieser Frage ist fast identisch mit Wann sollte ich ereignisbasierte Programmierung verwenden? Die Antworten auf diese Frage haben mir jedoch nicht bei der Entscheidung geholfen, ob ich Ereignisse in dem speziellen Fall verwenden soll, in dem ich mich befinde.
Ich entwickle eine kleine Anwendung. Es ist eine einfache App, deren Funktionalität zum größten Teil einfach CRUD ist.
Bei bestimmten Ereignissen (beim Ändern bestimmter Daten) muss die Anwendung eine lokale Kopie dieser Daten in eine Datei schreiben. Ich bin mir nicht sicher, wie ich das am besten umsetzen kann. Ich kann:
- Lösen Sie Ereignisse aus, wenn die Daten geändert werden, und binden Sie eine Antwort (generieren Sie die Datei) an solche Ereignisse. Alternativ können Sie das Beobachtermuster implementieren. Das scheint unnötig kompliziert zu sein.
- Rufen Sie den dateierzeugenden Code direkt aus dem Code auf, der die Daten ändert. Viel einfacher, aber es scheint falsch, dass die Abhängigkeit auf diese Weise sein sollte, das heißt, es scheint falsch, dass die Kernfunktionalität der App (Code, der Daten ändert) mit diesem zusätzlichen Vorteil (Code, der eine Sicherungsdatei generiert) gekoppelt werden sollte. Ich weiß jedoch, dass sich diese App nicht zu einem Zeitpunkt entwickeln wird, an dem diese Kopplung ein Problem darstellt.
Was ist in diesem Fall der beste Ansatz?
Antworten:
Befolgen Sie das KISS-Prinzip: Halten Sie es einfach, dumm oder das YAGNI-Prinzip: Sie werden es nicht brauchen.
Sie können den Code wie folgt schreiben:
Oder Sie können Code schreiben wie:
Wenn kein zwingender Grund vorliegt, etwas anderes zu tun, folgen Sie dem einfacheren Weg. Techniken wie die Ereignisbehandlung sind leistungsstark, erhöhen jedoch die Komplexität Ihres Codes. Es erfordert mehr Code, um zu funktionieren, und es erschwert die Verfolgung der Code-Vorgänge.
Ereignisse sind in der richtigen Situation sehr kritisch (stellen Sie sich vor, Sie würden versuchen, die Benutzeroberfläche ohne Ereignisse zu programmieren!). Verwenden Sie sie jedoch nicht, wenn Sie stattdessen KISS oder YAGNI können.
quelle
Das von Ihnen beschriebene Beispiel für einfache Daten, bei denen die Änderung einen gewissen Effekt auslöst, kann mit dem Beobachter-Entwurfsmuster perfekt implementiert werden :
Ein ereignisgesteuerter Ansatz lohnt sich für komplexere Szenarien, in denen viele verschiedene Wechselwirkungen auftreten können, in einem Many-to-Many-Kontext oder wenn Kettenreaktionen vorgesehen sind (z. B. informiert ein Subjekt einen Beobachter, der in einigen Fällen die Daten ändern möchte) Fach oder andere Fächer)
quelle
Wie Sie sagen, sind Ereignisse ein großartiges Werkzeug, um die Kopplung zwischen Klassen zu verringern. Es kann zwar erforderlich sein, zusätzlichen Code in einigen Sprachen zu schreiben, ohne dass Ereignisse unterstützt werden, dies verringert jedoch die Komplexität des Gesamtbilds.
Ereignisse sind wohl eines der wichtigsten Werkzeuge in OO (laut Alan Kay kommunizieren Objekte durch das Senden und Empfangen von Nachrichten ). Wenn Sie eine Sprache verwenden, die Ereignisse unterstützt, oder Funktionen als erstklassige Bürger behandelt, ist ihre Verwendung ein Kinderspiel.
Sogar in Sprachen ohne eingebaute Unterstützung ist die Menge an Boilerplate für etwas wie das Observer-Muster ziemlich gering. Möglicherweise finden Sie irgendwo eine anständige generische Eventing-Bibliothek, die Sie in all Ihren Anwendungen verwenden können, um das Boilerplate zu minimieren. (Ein generischer Ereignisaggregator oder Ereignismediator ist in nahezu jeder Anwendung nützlich.)
Lohnt es sich in einer kleinen Anwendung? Ich würde definitiv ja sagen .
Wenn Sie denken "Oh, aber es ist wirklich nur eine sehr kleine Anwendung, es ist wirklich nicht so wichtig" , bedenken Sie:
Insgesamt sollte die Größe einer Anwendung kein entscheidender Faktor dafür sein, ob Klassen lose gekoppelt bleiben sollen. SOLID-Prinzipien gelten nicht nur für große Anwendungen, sondern für Software und Codebasen in jeder Größenordnung.
Tatsächlich sollte die Zeitersparnis beim Unit-Testen Ihrer lose gekoppelten Klassen für sich genommen die zusätzliche Zeit ausgleichen, die zum Entkoppeln dieser Klassen aufgewendet wurde.
quelle
Das Beobachtermuster kann viel kleiner implementiert werden, als der Wikipedia-Artikel (oder das GOF-Buch) es beschreibt, vorausgesetzt, Ihre Programmiersprachen unterstützen so etwas wie "Rückrufe" oder "Delegierte". Übergeben Sie einfach eine Callback-Methode in Ihren CRUD-Code (die Observer-Methode, die entweder eine generische Methode zum Schreiben in eine Datei oder eine leere Methode sein kann). Anstelle von "Ereignisauslösung" rufen Sie einfach diesen Rückruf auf.
Der resultierende Code ist nur minimal komplexer als der direkte Aufruf des dateierzeugenden Codes, jedoch ohne die Nachteile einer engen Kopplung nicht verwandter Komponenten.
Das bringt Ihnen "das Beste aus beiden Welten", ohne die Entkopplung für "YAGNI" zu opfern.
quelle