Wann sind Haken die richtige Wahl?

10

Ich habe an einer großen Rails-App gearbeitet, in der die Verwendung von ActiveRecord-Rückrufen weit verbreitet und erschütternd war. Das Speichern eines Datensatzes hatte oft unerwartete Nebenwirkungen und es war eine Herausforderung, über das System nachzudenken.

Gleichzeitig habe ich Hooks gesehen, die als Teil der Vererbung (z. B. eine übergeordnete Klasse, die eine Vorlagenmethode verwendet, um Unterklassen das Hinzufügen von spezialisiertem Verhalten zu ermöglichen, ohne über die Interna der übergeordneten Elemente Bescheid wissen zu müssen) und Plug-Ins (z. B. ein Emacs-Modus, in dem ein Hook ausgeführt wird, wenn er aktiviert ist, sodass Benutzer in diesem Modus benutzerdefiniertes Verhalten hinzufügen können).

Mir ist klar, dass eine Rails-App und ein Lisp-Interpreter sehr unterschiedliche Systeme sind, aber ich bin gespannt, ob es bekannte Kriterien gibt, nach denen die Leute suchen, wenn sie entscheiden, ob Hooks die richtige Designwahl für das Problem sind, mit dem sie konfrontiert sind.

Das Thema, das mich anspricht, ist Vorhersehbarkeit. Der Missbrauch von Haken scheint in der Ferne zu gruseligen Aktionen und überraschendem Verhalten zu führen, während eine gute Verwendung zu einem Rahmen führen kann, der ohne enge Kopplung vorhersehbar ist.

Da ich noch ein paar Jahre in meiner Programmierkarriere bin, betrachte ich mich in vielerlei Hinsicht als Noob, und verdächtige Leute haben viel über dieses Thema nachgedacht. Welche Richtlinien können diese Entscheidung steuern?

ivan
quelle

Antworten:

5

Hooks sind eine gute Wahl für das Design, wenn Sie die Implementierungsdetails einer Abstraktion von ihren Verbrauchern entkoppeln möchten, indem Sie die Steuerung auf die Empfänger des Hooks übertragen.

Sie können dies durch eine anonyme Sendung (wie Ereignisse oder anonyme Rückrufe) oder durch Verwendung typisierter Abstraktionen (wie Schnittstellen oder übergeordnete Klassen) tun.

Sie sollten eine anonyme Sendung verwenden, wenn:

  • Der Aufruf des Hakens ist optional
  • Dem Anrufer ist es egal, wer den Haken erhält.
  • Die Reihenfolge der Ausführung der Empfänger ist unerheblich.
  • Sie möchten den Objektstatus an alle Abonnenten des Hooks senden.

Sie sollten eine typisierte Abstraktion verwenden, wenn:

  • Das Aufrufen des Hakens ist obligatorisch.
  • Das aufrufende Objekt muss den Empfänger des Hooks identifizieren.
  • Die Ausführungsreihenfolge der Empfänger ist für Ihr Objekt relevant.

Ein Beispiel für einen Broadcast-Hook ist ein KeyPressedEvent. Der Klasse, die das Ereignis auslöst, ist es egal, wer es empfängt, und sie sendet den Tastaturstatus an alle Personen, die das Ereignis abonniert haben. Die Ausführungsreihenfolge der Empfänger hat keine Auswirkung auf den Objektstatus der Klasse, die das Ereignis auslöst.

Ein Beispiel für einen typisierten Abstraktions-Hook ist die von Ihnen erwähnte Vorlagenmethode. In diesem Fall benötigt die übergeordnete Klasse eine Implementierung für ihre Vorlagenmethoden, sie weiß, dass die Empfänger untergeordnete Elemente davon sind, und sie hat eine bestimmte Ausführungsreihenfolge für die Vorlagenmethoden, wie von der übergeordneten Klasse definiert.

Cesar Hernandez
quelle
7

Die meisten Sprachen und Plattformen verwenden Hooking, auch wenn es als etwas anderes verkleidet ist. Wann immer Sie von dem Begriff "Ereignis", "Nachricht", "Auslöser", "Signal" oder anderen Begriffen dieser Art hören, haben Sie es wahrscheinlich mit Hooking zu tun, obwohl es Ausnahmen von der Regel gibt, die dies wahrscheinlich nicht tun Angelegenheit für diese Diskussion.

Sie verwenden sie, weil die Plattform sie Ihnen zur Verfügung stellt oder sie aus Leistungsgründen möglicherweise sogar benötigt. Die Verwendung von Hooks reduziert häufig die Codekomplexität, hilft bei der Durchsetzung von Geschäftsanforderungen und reduziert die CPU-Auslastung, wodurch die Lebensdauer von Batterie und Hardware verlängert wird. Sie sollten sie immer dann verwenden, wenn Sie die beste Leistung Ihres Codes erzielen möchten.

Selbst Ihre erschütternde Erfahrung mit Rails identifiziert einen häufigen Anwendungsfall für Hooks: Geschäftsregeln müssen durchgesetzt werden, und Hooks werden allgemein zur Durchsetzung von Geschäftsregeln verwendet. Leider sind nicht alle Regeln sinnvoll, und wie Sie sehen, ist es für Entwickler schwieriger, wenn sie willkürlich sind. Deshalb ist die Dokumentation eines Systems genauso wichtig wie der Code selbst.

Verwenden Sie in der Regel Hooks, da diese Leistungsmerkmale darstellen und Ihr Code effizienter ausgeführt wird als die Alternative (die als "Polling" bezeichnet wird, bei der Sie in einer Besetztschleife warten, um nach Ereignissen zu suchen). Stellen Sie jedoch auch sicher, dass Sie die entsprechende Dokumentation verwenden und auf dem neuesten Stand halten. Hooks werden in praktisch jeder Sprache verwendet, und es ist wichtig zu wissen, warum sie existieren.

Phyrfox
quelle
1

Ich habe zuvor an einem Programm gearbeitet, das meiner Meinung nach eine gute Verwendung von Hooks ermöglichte. In meinem Buch ist ein echter Haken ein Aufruf (Veröffentlichen) einer Liste von Rückrufen (Abonnenten). Es ist mächtig, Missbrauch ist einfach. Die beste Frage für den Anwendungsfall lautet: Möchte ich das Verhalten zur Laufzeit aktivieren oder deaktivieren? Beispielsweise möchten Sie Ihren Benutzern möglicherweise erlauben, Skripts bereitzustellen, die Sie bei bestimmten Ereignissen ausführen, oder ein generisches Programm aus kleineren Plugins erstellen. Dann sind Hook-Calls angebracht. Im Allgemeinen haben Sie kaum andere Möglichkeiten.

Wenn nicht, sollten Sie mit einem guten Bogen Ihrer Module davonkommen. Template-Methoden funktionieren gut mit überladenen Funktionen, dafür benötigen Sie keine Laufzeitlogik. Bedenken Sie, dass es eine Illusion erzwingen würde, wenn eine lose Kopplung erzwungen wird: Es gibt die gleiche Abhängigkeitsstufe zwischen etwas, das Sie direkt anrufen oder das Sie einhaken. Der Angerufene muss seinen Vertrag trotzdem erfüllen.

Beachten Sie, dass einige Leute möglicherweise die Template-Methode mit überladenem Funktions-Hooking aufrufen, aber das unterscheidet sich von den oben genannten: Hier haben Sie eine statische Verknüpfung mit einem geringeren Risiko, in einen Wartungs-Albtraum zu geraten.

Arthur Havlicek
quelle