Wenn eine Klasse etwas nicht tun kann (oder sollte), können Ereignisse oder Delegaten eine Lösung sein.
sagen
%Vor%Hier im Delegiertenansatz wird die Wissenschaftlermethode direkt von der Präsidentenklasse verwendet, falls ein Präsident eine Frage stellt und der Wissenschaftler darauf mit einer Antwort reagiert.
Im .NET Framework-Code habe ich allerdings den direkten Einsatz von Delegierten nicht beobachtet. Ist es falsch, es direkt zu benutzen, und wenn, warum?
Ist es falsch, es direkt zu benutzen, und wenn, warum?
Nein, es ist nicht falsch.
So denke ich darüber nach. Delegiertenfelder sind für Ereignisse, da Zeichenfolgenfelder für Eigenschaften stehen. Das heißt, Sie könnten:
%Vor%Der Modellname ist logisch eine Eigenschaft eines Autos. Wenn dich jemand fragt, was für ein Auto du fährst und du sagst "ein Ford Focus", beschreibst du eine Eigenschaft des Autos. Sie denken nicht an "Ford Focus" als ein "Feld" oder eine "Schnur", Sie denken, es ist der Name einer Art von Auto. In dem Computerprogramm ist das Zeichenfolgenfeld nur das Implementierungsdetail, wie der Name gespeichert wird. Die Eigenschaft könnte eine Zeichenfolge sein oder eine Enumeration oder was auch immer; Der Punkt ist, dass Autos logischerweise Modellnamen haben, keine Stringfelder.
Veranstaltungen und Delegierte sind auf die gleiche Art und Weise. Ein Auto kann ein "explodieren" -Ereignis haben (vielleicht schreibst du ein Videospiel!) Und das explodierende Ereignis wird durch ein Feld des Delegattyps implementiert. Explodieren ist etwas, was das Auto logisch macht; Das Delegate-Feld ist der Mechanismus, mit dem das Ereignis implementiert wird.
Ist es also "falsch", Delegierte direkt zu verwenden? Nein natürlich nicht. Nicht mehr als "falsch", Strings direkt zu verwenden. Manchmal müssen Sie Zeichenfolgen bearbeiten, die keine Eigenschaften sind, und manchmal müssen Sie Delegaten bearbeiten, die keine Ereignisse sind.
Der Trick besteht darin, Code zu schreiben, der die mechanischen Prozesse von den Business Prozessen eindeutig trennt. Wenn Sie feststellen, dass Sie eine Menge String-Logik mit Ihrer Eigenschaftslogik mischen oder eine Vielzahl von Delegatemanipulationen mit Ihren Ereignissen mischen, sollten Sie vielleicht in Betracht ziehen, den Mechanismuscode ein wenig mehr von dem Geschäftscode zu trennen ist einfacher zu sehen, welches was ist.
Im Rahmen wird viel von Delegierten Gebrauch gemacht. LINQ ist ein klares Beispiel dafür:
%Vor% Where
verwendet einen Delegaten mit einer bestimmten Signatur, die aufgerufen wird, um festzustellen, ob ein Element in das Ergebnis aufgenommen werden soll oder nicht. Die gebräuchlichste Verwendung ist der lamba-Ansatz, wie oben gezeigt, aber Sie können auch eine Methode übergeben:
int.Parse
stimmt mit der erforderlichen Delegiertensignatur überein, die Select
in diesem Fall erwartet ( Func<string,int>
), daher wird sie für jede Zeichenfolge in nums
aufgerufen.
Wenn Delegaten direkt verwendet werden, werden sie normalerweise als Eingabe für Methodenaufrufe verwendet, die sie verwenden. Es gibt jedoch einige Orte, an denen sie Teil des Konsumentenstatus sind ( HttpListener
hat zum Beispiel einige Eigenschaften von Delegattypen, aber sie sind nicht so viele.
Die Arbeit mit Delegierten im Rohzustand kann einiges mit sich bringen Textbausteincode (Definieren des Delegaten, Deklarieren der erforderlichen Elementvariablen und Erstellen von Benutzerdefinitionen Methoden zur Registrierung / Aufhebung der Registrierung, um die Kapselung usw. beizubehalten.).
Abgesehen von der Zeit, ein weiteres Problem bei der Verwendung von Delegaten im Raw-Format als Callback Ihrer Anwendung Mechanismus ist die Tatsache, dass, wenn Sie nicht die Delegiertenmitgliedsvariablen einer Klasse als private definieren Der Aufrufer hat direkten Zugriff auf die Delegatobjekte. Wenn dies der Fall wäre, könnte der Anrufer dazu in der Lage sein Weisen Sie die Variable einem neuen Delegate-Objekt zu (Löschen der aktuellen Liste der Funktionen für Call) und schlimmer noch, der Aufrufer wäre in der Lage, die Aufrufliste des Delegierten direkt aufzurufen.
Ereignisse
Ereignisse sind eigentlich eines der Dinge, die ich an .net wirklich mag, weil es Ihnen erlaubt, eine viel sauberere Schnittstelle zu deklarieren. Sie können eine Präsidentenklasse haben, die ankündigt, dass sie eine Antwort benötigt, ohne sie an die Implementierung des antwortenden Agenten wie
zu binden %Vor%und dann in deiner Wissenschaftlerklasse
%Vor%Wenn eine neue Klasse die Fragen des Präsidenten beantworten will, muss sie nur auf das Ereignis hören, das signalisiert, dass eine Frage beantwortet werden muss, und sie dann beantworten, wenn sie dazu in der Lage ist. Wenn der Wissenschaftler Fragen von jemand anderem beantworten möchte, müssen wir nur eine Methode implementieren, die an ihr Ereignis anknüpft.
direkter Delegataufruf
Das Problem mit dem Delegat-Ansatz, den Sie oben skizziert haben, ist, dass es die Kapselung durchbricht. Es verbindet die Implementierungen von Wissenschaftlern und Präsidenten eng und macht den Code spröde. Was passiert, wenn Sie eine andere Person haben, die Fragen beantwortet? In Ihrem Beispiel müssen Sie Ihre Implementierung von Scientist modifizieren, um neue Funktionalität hinzuzufügen, die als "spröder" Code bezeichnet wird, und ist eine schlechte Sache. Diese Technik hat eine gewisse Rolle in der Komposition, aber sie wird nur selten, wenn überhaupt, die beste Wahl sein.
Der linq-Fall ist anders, weil Sie keinen Delegaten als Mitglied einer Klasse / Schnittstelle offenlegen. Stattdessen verwenden Sie es als Funktor, der vom Aufrufer deklariert wird, um Sie darüber zu informieren, an welchen Informationen der Aufrufer interessiert ist. Da Sie eine "Round-Trip" -Kapselung durchführen, bleibt die Kapselung intakt. Auf diese Weise können Sie sehr saubere und leistungsfähige APIs definieren.
Wir könnten das Beispiel des Wissenschaftlers nehmen und es mit dieser Technik erweitern, damit jemand herausfinden kann, welche Fragen wir so beantworten können
%Vor% Beachten Sie, dass wir mit der Methode FindQuestions
nicht einen Haufen anderen Code implementieren müssen, um den Wissenschaftler zu befragen, den wir benötigt hätten, ohne die Delegierten herumführen zu können. Während dies nicht der einzige Fall ist, in dem Sie Delegierte finden, die direkt aufgerufen werden, ist dies eine der häufigsten.