7

Observer パターンを VB.NET や C#、その他の一流の .NET 言語で実装しようと考えています。これにはデリゲートを使用できると聞いたことがありますが、オブザーバーに実装されたプレーンな古いインターフェイスよりもデリゲートが好まれる理由がわかりません。そう、

  • 独自のインターフェイスを定義し、それらを実装するオブジェクトへの参照を渡す代わりに、デリゲートを使用する必要があるのはなぜですか?
  • デリゲートの使用を避けて、古き良き時代のインターフェイスを使用する必要があるのはなぜですか?
4

14 に答える 14

27

メソッドを直接呼び出すことができる場合、デリゲートは必要ありません。

デリゲートは、メソッドを呼び出すコードが、呼び出しているメソッドが何であるかを認識していない/気にしない場合に役立ちます。たとえば、長時間実行されるタスクを呼び出して、タスクが使用できるコールバック メソッドにデリゲートを渡します。そのステータスに関する通知を送信します。

これは(非常にばかげた)コードサンプルです:

enum TaskStatus
{
   Started,
   StillProcessing,
   Finished
}

delegate void CallbackDelegate(Task t, TaskStatus status);

class Task
{
    public void Start(CallbackDelegate callback)
    {
        callback(this, TaskStatus.Started);

        // calculate PI to 1 billion digits
        for (...)
        {
            callback(this, TaskStatus.StillProcessing);
        }

        callback(this, TaskStatus.Finished);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Task t = new Task();
        t.Start(new CallbackDelegate(MyCallbackMethod));
    }

    static void MyCallbackMethod(Task t, TaskStatus status)
    {
        Console.WriteLine("The task status is {0}", status);
    }
}

ご覧のとおり、Taskクラスは、この場合、タスクのステータスをコンソールに出力するメソッドに対するデリゲートであることを知りません。この方法では、ネットワーク接続を介してステータスを別のコンピューターに送信することもできます。等。

于 2010-06-28T17:25:56.420 に答える
22

あなたは O/S で、私はアプリケーションです。何かが起こっていることを検出したら、私のメソッドの 1 つを呼び出すように伝えたいと思います。そのために、呼び出してもらいたい私のメソッドへのデリゲートを渡します。何かを検出したときに呼び出してほしいので、私自身はそのメソッドを呼び出しません。メソッドが存在することを(コンパイル時に)知らないため、メソッドを直接呼び出すことはありません(作成時に作成されていませんでした)。代わりに、実行時に受け取ったデリゲートによって指定されたメソッドを呼び出します。

于 2010-06-28T17:25:15.300 に答える
9

技術的には、デリゲートを使用する必要はありません (イベント ハンドラーを使用する場合を除き、必須です)。あなたはそれらなしでやっていくことができます。本当に、それらはツール ボックスの別のツールにすぎません。

それらを使用して最初に頭に浮かぶのは、Inversion Of Controlです。関数が外部からどのように動作するかを制御したいときはいつでも、それを行う最も簡単な方法は、デリゲートをパラメーターとして配置し、デリゲートを実行させることです。

于 2010-06-28T17:24:55.417 に答える
6

あなたはプログラマーのように考えていません。

問題は、デリゲートを呼び出すことができるのに、なぜ関数を直接呼び出すのでしょうか?

David Wheeler の有名な格言は次のとおりです。コンピューター サイエンスのすべての問題は、別のレベルの間接化によって解決できます。

私は少し冗談を言っています。明らかに、ほとんどの場合、特にモジュール内で関数を直接呼び出します。ただし、デリゲートは、イベント コールバックなど、含まれるオブジェクトが使用できない (または関連しない) コンテキストで関数を呼び出す必要がある場合に役立ちます。

于 2010-06-28T17:28:19.303 に答える
4

Observer パターンでデリゲートを使用できる場所が 2 つあります。どちらのことを言っているのかわからないので、両方答えようと思います。

1 つ目は、サブジェクトで IObserver のリストの代わりにデリゲートを使用することです。このアプローチは、基本的に

private delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(IObserver observer)
{
    Update+=observer.Update;
}

public void Unregister(IObserver observer)
{
    Update-=observer.Update;
}

public void Notify(string message)
{
    Update(message);
}

それ以外の

public Subject()
{
    observers = new List<IObserver>();
}

public void Register(IObserver observer)
{
    observers.Add(observer);
}

public void Unregister(IObserver observer)
{
    observers.Remove(observer);
}

public void Notify(string message)
{
    // call update method for every observer
    foreach (IObserver observer in observers)
    {
        observer.Update(message);
    }
}

特別なことをする必要がなく、IObserver オブジェクト全体への参照が必要な場合を除き、デリゲートの方がすっきりすると思います。

2 番目のケースは、たとえば IObervers の代わりに pass デリゲートを使用することです。

public delegate void UpdateHandler(string message);
private UpdateHandler Update;

public void Register(UpdateHandler observerRoutine)
{
    Update+=observerRoutine;
}

public void Unregister(UpdateHandler observerRoutine)
{
    Update-=observerRoutine;
}

public void Notify(string message)
{
    Update(message);
}

これにより、オブザーバーはインターフェースを実装する必要がなくなります。ラムダ式を渡すこともできます。この制御レベルの変化は、かなりの違いです。これが良いか悪いかはあなた次第です。

于 2008-11-19T18:47:22.337 に答える
2

この質問に対する回答を繰り返します。

私はいつもラジオ局の比喩が好きです。

ラジオ局が何かを放送したいときは、それを送信するだけです。実際に誰かが聞いているかどうかを知る必要はありません。ラジオは (ダイヤルでチューニングすることにより) ラジオ局に登録することができ、すべてのラジオ局のブロードキャスト (私たちの小さなメタファーでのイベント) は、それらを音に変換するラジオによって受信されます。

この登録 (またはイベント) メカニズムなし。ラジオ局は、すべてのラジオに順番に連絡して、放送が必要かどうかを尋ね、ラジオが「はい」と言ったら、信号を直接送信する必要があります。

あなたのコードは、1 つのクラスがアクションを実行する非常によく似たパラダイムに従う場合がありますが、そのクラスは、誰がそのアクションを気にするか、またはそのアクションに対して行動するかを知らないか、知りたくない場合があります。したがって、アクションが発生したことを通知するために、任意のオブジェクトがそれ自体を登録または登録解除する方法を提供します。

于 2010-06-28T17:25:44.113 に答える
2

デリゲートは、関数/メソッド インターフェイスの強力な型指定です。

あなたの言語が強い型付けが必要であり、ファーストクラスの関数を持っているという立場をとっている場合 (C# はどちらもそうです)、デリゲートを持たないことは一貫性がありません。

デリゲートを取るメソッドを検討してください。デリゲートがなかったら、どのようにデリゲートに何かを渡しますか? そして、呼び出し先はその型についてどのように保証しますか?

于 2010-06-28T17:26:20.163 に答える
2

デリゲートは、実際には、オブジェクトではなくメソッドへの参照を渡しています...インターフェイスは、オブジェクトによって実装されたメソッドのサブセットへの参照です...

アプリケーションの一部のコンポーネントで、オブジェクトの複数のメソッドにアクセスする必要がある場合は、オブジェクトのメソッドのサブセットを表すインターフェイスを定義し、これに渡す必要があるすべてのクラスにそのインターフェイスを割り当てて実装しますコンポーネント...次に、これらのクラスのインスタンスを、具体的なクラスではなく、そのインターフェイスで渡します..

一部のメソッドまたはコンポーネントで、必要なのはいくつかのメソッドの 1 つだけであり、それらは任意の数の異なるクラスに含まれる可能性がありますが、すべてが同じ署名を持っている場合は、デリゲートを使用する必要があります。

于 2008-11-19T18:31:56.050 に答える
1

実際、デリゲートに関して Sun と Microsoft の間で興味深いやり取りがありました。Sun はデリゲートに対してかなり強い姿勢を示しましたが、Microsoft はデリゲートの使用をさらに強く主張しているように感じます。投稿は次のとおりです。

http://java.sun.com/docs/white/delegates.html

http://msdn.microsoft.com/en-us/vjsharp/bb188664.aspx

これらの興味深い読み物が見つかると思います...

于 2010-06-28T18:27:07.407 に答える
1

何人かの「イベント エバンジェリスト」がこれについて話しているのを聞いたことがあります。

できれば、イベント ソースがイベント リスナを認識しないようにする必要があり、イベント リスナがイベントの発信者を気にしないようにする必要があります。イベントリスナーでは通常、イベントのソースオブジェクトを受け取るため、これは今日の状況ではありません。

そうは言っても、デリゲートはこの仕事に最適なツールです。イベント ソースはすべてのオブザーバー オブジェクトのリストを保持する必要がないため、イベント ソースとイベント オブザーバーを切り離すことができます。オブザーバーの「関数ポインター」(デリゲート)のリストのみを保持します。このため、これは Interfaces に対する大きな利点だと思います。

于 2008-11-19T18:36:01.410 に答える
1

他の方法でそれを見てください。構文とライブラリの両方で言語によってサポートされている標準的な方法を使用するよりも、カスタム インターフェイスを使用する利点は何ですか?

確かに、カスタマイズされたソリューションに利点がある場合があり、そのような場合はそれを使用する必要がありますそれ以外の場合は、利用可能な最も標準的なソリューションを使用してください。手間がかからず、直感的で (ユーザーが期待しているため)、ツール (IDE を含む) からのサポートが多く、コンパイラがそれらを別の方法で処理するため、より効率的なコードが得られる可能性があります。

車輪を再発明しないでください (現在のバージョンが壊れていない限り)。

于 2008-11-19T18:40:58.747 に答える
0

役立つ例を次に示します。

大量のデータを使用するアプリケーションがあります。データをフィルタリングできる機能が必要です。6 種類のフィルターを指定できます。

すぐに考えられるのは、それぞれがフィルタリングされたデータを返す 6 つの異なるメソッドを作成することです。例えば

public Data FilterByAge(int age)

public Data FilterBySize(int サイズ)

.... 等々。

これは問題ありませんが、非常に制限されており、拡張のために閉じられているため、無駄なコードが生成されます。

より良い方法は、単一の Filter メソッドを使用して、データをフィルター処理する方法に関する情報を渡すことです。ここでデリゲートを使用できます。デリゲートは、データをフィルター処理するためにデータに適用できる関数です。

public Data Filter(アクションフィルター)

これを使用するコードは次のようになります

フィルター (データ => data.age > 30);

フィルター (データ => data.size = 19);

コード データ => 何とか何とかデリゲートになります。コードはより柔軟になり、オープンなままになります。

于 2011-10-03T09:17:13.753 に答える
0

これは、デリゲートを使用する理由として書き留めることができるものです。次のコードは C# で記述されています。コメントに従ってください。

public delegate string TestDelegate();
protected void Page_Load(object sender, EventArgs e)
{
    TestDelegate TD1 = new TestDelegate(DiaplayMethodD1);
    TestDelegate TD2 = new TestDelegate(DiaplayMethodD2);
    TD2 = TD1 + TD2; // Make TD2 as multi-cast delegate
    lblDisplay.Text =  TD1(); // invoke delegate
    lblAnotherDisplay.Text = TD2();


    // Note: Using a delegate allows the programmer to encapsulate a reference 
    //       to a method inside a delegate object. Its like the function pointer
    //       in C or C++.    
}
//the Signature has to be same.
public string DiaplayMethodD1()
{
    //lblDisplay.Text = "Multi-Cast Delegate on EXECUTION"; // Enable on multi-cast 
    return "This is returned from the first method of delegate explanation";
}
// The Method can be static also
public static string DiaplayMethodD2()
{
    return " Extra words from second method";
}

敬具、 Pritom Nandy、バングラデシュ

于 2010-12-20T09:21:01.013 に答える
0

私はそれがシンタティックシュガーとコードを整理する方法にもっと関連していると思います.オブジェクトまたは静的クラスに属する共通のコンテキストに関連するいくつかのメソッドを処理することをお勧めします.

それらを使用することを強制されているわけではありません。それらを使用しても使用しなくてもsthをプログラムできますが、使用するかどうかは、コードの整理、読みやすさ、およびコードのクールではない理由に影響を与える可能性があります。

ここに示すすべての例は、実装できる良い例です。誰かが言ったように、言語のもう 1 つの機能であり、遊ぶことができます。

挨拶

于 2010-06-28T19:28:14.947 に答える