Ich möchte das Observer-Muster in VB.NET oder C # oder einer anderen erstklassigen .NET-Sprache implementieren. Ich habe gehört, dass Delegierte dafür verwendet werden können, aber ich kann nicht herausfinden, warum sie gegenüber einfachen alten Schnittstellen, die bei Beobachtern implementiert sind, bevorzugt werden. Also,
Wenn Sie eine Methode direkt aufrufen können, benötigen Sie keinen Delegaten.
Ein Delegat ist nützlich, wenn der Code, der die Methode aufruft, nicht weiß, wie die Methode lautet - Sie können z. B. eine lang andauernde Aufgabe aufrufen und ihr einen Delegaten übergeben zu einer Callback-Methode, mit der die Task Benachrichtigungen über ihren Status senden kann.
Hier ist ein (sehr dummes) Codebeispiel:
%Vor% Wie Sie sehen können, weiß die Task
-Klasse nicht, dass in diesem Fall der Delegat eine Methode ist, die den Status der Aufgabe an die Konsole ausgibt. Die Methode könnte genauso gut den Status über eine Netzwerkverbindung an einen anderen Computer senden. Etc.
Sie sind ein O / S und ich bin eine Anwendung. Ich möchte dir sagen, dass du eine meiner Methoden aufrufen solltest, wenn du feststellst, dass etwas passiert. Um dies zu tun, gebe ich Ihnen einen Delegierten an die Methode von mir, die ich Sie anrufen möchte. Ich nenne diese Methode nicht von mir selbst, weil ich möchte, dass du sie nennst, wenn du etwas erkennst. Sie rufen meine Methode nicht direkt auf, weil Sie (zu Ihrer Kompilierzeit) nicht wissen, dass die Methode existiert (ich wurde nicht einmal geschrieben, als Sie gebaut wurden); Stattdessen rufen Sie die Methode auf, die von dem Delegat angegeben wird, den Sie zur Laufzeit erhalten.
Technisch gesehen müssen Sie keine Delegierten verwenden (außer wenn Sie Eventhandler verwenden, dann ist es erforderlich). Sie können ohne sie auskommen. Wirklich, sie sind nur ein weiteres Werkzeug in der Toolbox.
Das erste, was ihnen einfällt, ist Inversion Of Control . Jedes Mal, wenn Sie steuern möchten, wie sich eine Funktion von außerhalb verhält, ist es am einfachsten, einen Delegaten als Parameter zu platzieren und den Delegaten auszuführen.
Sie denken nicht wie ein Programmierer.
Die Frage ist, warum würden Sie eine Funktion direkt aufrufen, wenn Sie einen Delegierten anrufen könnten ?
Ein berühmter Aphorismus von David Wheeler geht: Alle Probleme in der Informatik kann durch eine andere Ebene gelöst werden Indirektion.
Ich bin ein bisschen ironisch. Offensichtlich werden Sie die Funktionen meistens direkt aufrufen, besonders innerhalb eines Moduls. Delegaten sind jedoch nützlich, wenn eine Funktion in einem Kontext aufgerufen werden muss, in dem das enthaltene Objekt nicht verfügbar (oder relevant) ist, z. B. Ereignisrückrufe.
Es gibt zwei Orte, an denen Sie Delegaten im Observer-Muster verwenden könnten. Da ich mir nicht sicher bin, auf welche Sie sich beziehen, werde ich versuchen, beides zu beantworten.
Die erste besteht darin, Delegaten im Betreff anstelle einer Liste von IO-Servern zu verwenden. Dieser Ansatz scheint beim Umgang mit Multicasting viel sauberer zu sein, da Sie im Grunde
haben %Vor%statt
%Vor%Wenn Sie nicht etwas Spezielles tun müssen und einen Verweis auf das gesamte IObserver-Objekt benötigen, würde ich denken, dass die Delegierten sauberer sind.
Der zweite Fall ist die Verwendung von Pass-Delegaten anstelle von IObervers, zum Beispiel
%Vor%Damit brauchen Beobachter keine Schnittstelle zu implementieren. Sie könnten sogar einen Lambda-Ausdruck eingeben. Diese Veränderung des Kontrolllevels ist ziemlich genau der Unterschied. Ob das gut oder schlecht ist, liegt an dir.
Ein Delegat gibt tatsächlich einen Verweis auf eine Methode weiter, nicht auf ein Objekt ... Eine Schnittstelle ist eine Referenz auf eine Teilmenge der von einem Objekt implementierten Methoden ...
Wenn Sie in einer Komponente Ihrer Anwendung Zugriff auf mehr als eine Methode eines Objekts benötigen, definieren Sie eine Schnittstelle, die diese Teilmenge der Methoden des Objekts darstellt, und weisen Sie diese Schnittstelle allen Klassen zu, die Sie möglicherweise benötigen Übergeben Sie diese Komponente ... Übergeben Sie dann die Instanzen dieser Klassen an dieser Schnittstelle und nicht an ihrer konkreten Klasse.
Wenn, otoh, in einer Methode oder in einer Komponente, brauchen Sie nur eine von mehreren Methoden, die in einer beliebigen Anzahl von verschiedenen Klassen sein können, aber alle die gleiche Signatur haben, dann müssen Sie einen Delegaten verwenden.
Ich wiederhole eine Antwort, die ich diese Frage .
Ich mag die Metapher des Radiosenders immer.
Wenn ein Radiosender etwas senden möchte, sendet er es einfach aus. Es muss nicht wissen, ob tatsächlich jemand da draußen zuhört. Ihr Radio kann sich beim Radiosender registrieren (indem es sich mit dem Wahlrad einstellt), und alle Radiosender-Sendungen (Ereignisse in unserer kleinen Metapher) werden vom Radio empfangen, das sie in Ton umsetzt.
Ohne diesen Registrierungs- (oder Ereignis-) Mechanismus. Der Radiosender müsste nacheinander jedes Radio kontaktieren und fragen, ob es die Sendung wollte, wenn Ihr Radio ja sagt, dann senden Sie das Signal direkt an dieses.
Ihr Code kann einem sehr ähnlichen Paradigma folgen, bei dem eine Klasse eine Aktion ausführt, aber diese Klasse kann nicht wissen oder nicht wissen, wer sich um diese Aktion kümmern wird oder welche Aktion stattfinden soll. So bietet es jedem Objekt die Möglichkeit, sich selbst zu registrieren oder die Registrierung aufzuheben, um zu melden, dass die Aktion stattgefunden hat.
Delegierte tippen stark auf Funktions / Methoden-Schnittstellen.
Wenn Ihre Sprache die Position einnimmt, dass es eine starke Typisierung geben sollte, und dass sie erstklassige Funktionen hat (beide von C #), dann wäre es inkonsequent zu nicht Delegaten.
Betrachten Sie jede Methode, die einen Delegaten erfordert. Wenn Sie keinen Delegierten hätten, wie würden Sie ihm etwas geben? Und wie hätte der Angerufene irgendwelche Garantien für seinen Typ?
Ich habe einige "evangelists events" darüber reden hören und sie sagen, dass je mehr entkoppelte Ereignisse sind, desto besser ist es.
Vorzugsweise sollte die Ereignisquelle niemals über die Ereignis-Listener informiert werden, und der Ereignis-Listener sollte sich nie darum kümmern, von wem das Ereignis stammt. So ist es heute nicht, denn im Ereignis-Listener erhalten Sie normalerweise das Quellobjekt des Ereignisses.
Damit sind Delegierte das perfekte Werkzeug für diesen Job. Sie ermöglichen die Entkopplung zwischen Ereignisquelle und Ereignisbeobachter, da die Ereignisquelle keine Liste aller Observer-Objekte führen muss. Es führt nur eine Liste von "Funktionszeigern" (Delegaten) der Beobachter. Aus diesem Grund denke ich, dass dies ein großer Vorteil gegenüber Interfaces ist.
Sieh es dir anders an. Welchen Vorteil hätte die Verwendung einer benutzerdefinierten Schnittstelle gegenüber dem Standard, der von der Sprache sowohl in der Syntax als auch in der Bibliothek unterstützt wird?
Zugegeben, dort sind Fälle, in denen eine maßgeschneiderte Lösung Vorteile haben könnte, und in solchen Fällen sollten Sie sie verwenden. In allen anderen Fällen verwenden Sie die kanonischste verfügbare Lösung. Es ist weniger Arbeit, intuitiver (weil es das ist, was Benutzer erwarten), hat mehr Unterstützung von Werkzeugen (einschließlich der IDE) und die Chancen sind, der Compiler behandelt sie anders, was zu effizienterem Code führt.
Erfinde das Rad nicht neu (es sei denn, die aktuelle Version ist defekt).
Tatsächlich gab es ein interessantes Hin und Her zwischen Sun und Microsoft über Delegierte. Während Sun gegenüber den Delegierten eine ziemlich starke Haltung eingenommen hat, habe ich das Gefühl, dass Microsoft einen noch stärkeren Stellenwert für die Verwendung von Delegierten hat. Hier sind die Beiträge:
Ich denke, Sie werden diese interessanten Lektüre finden ...
Ich denke, dass es mehr mit syntaktischem Zucker zusammenhängt und eine Möglichkeit, Ihren Code zu organisieren, wäre es, mehrere Methoden zu verwenden, die mit einem gemeinsamen Kontext zu tun haben Klasse.
Es ist nicht so, dass Sie gezwungen sind, sie zu verwenden, Sie können etw programmieren mit und ohne sie, aber vielleicht kann es sich auswirken, wie organisiert, lesbar und warum nicht cool der Code sein könnte, vielleicht ein paar Zeilen in Ihrem Code.
Jedes hier gegebene Beispiel ist ein gutes Beispiel, in dem Sie sie implementieren können, wie jemand sagte, es ist nur ein weiteres Feature in der Sprache, mit der Sie spielen können.
Grüße
Hier ist etwas, das ich als Grund für die Verwendung von Delegaten aufschreiben kann. Der folgende Code ist in C # geschrieben. Bitte folgen Sie den Kommentaren.
%Vor%Mit freundlichen Grüßen, Pritom Nandy, Bangladesch
Hier ist ein Beispiel, das helfen könnte.
Es gibt eine Anwendung, die eine große Menge von Daten verwendet. Es wird eine Funktion benötigt, mit der die Daten gefiltert werden können. 6 verschiedene Filter können angegeben werden.
Der unmittelbare Gedanke besteht darin, 6 verschiedene Methoden zu erstellen, die jeweils die gefilterten Daten zurückgeben. Zum Beispiel
public Data FilterByAge (int age)
public Data FilterBySize (int Größe)
.... und so weiter.
Das ist in Ordnung, aber es ist sehr begrenzt und erzeugt Müllcode, weil er für die Erweiterung geschlossen ist.
Eine bessere Möglichkeit besteht darin, eine einzelne Filtermethode zu verwenden und Informationen darüber zu übermitteln, wie die Daten gefiltert werden sollen. Hier kann ein Delegat verwendet werden. Der Delegat ist eine Funktion, die auf die Daten angewendet werden kann, um sie zu filtern.
öffentlicher Datenfilter (Aktionsfilter)
Dann wird der Code, der verwendet wird,
Filter (Daten = & gt; data.age & gt; 30);
Filter (Daten = & gt; data.size = 19);
Die Codedaten = & gt; Blabla wird zum Delegierten. Der Code wird viel flexibler und bleibt offen.
Tags und Links .net design-patterns delegates