タイトル | : Re^3: デリゲートについて |
記事No | : 4664 |
投稿日 | : 2006/12/14(Thu) 12:05 |
投稿者 | : 魔界の仮面弁士 |
> のような感じなら素直に関数呼べばいいんじゃないかと思うわけでして・・・
それは、渡す相手が「自分自身」だった場合ですよね。 「他人」に処理を依頼する場合は、直接呼べるとは限らないわけで。
------- たとえば、Buttonコントロールを考えてみてください。 これは、ユーザがクリック操作したときに、任意の処理を発生させるクラスです。
そして、フォーム上には、Button1_Click メソッドを用意してあります。 通常は、ButtonのClickイベントを使って、このメソッドが実行されますよね。
では、これをあえて、「イベント抜き」で考えてみましょう。
もし、その処理クラスを自分で作っているのであれば、処理クラス側から直接、 mainForm.MyMethod(…) などと書いて、処理対象のメソッドを直接実行させることが可能ですね。
でも、それだと「依頼側クラス」と「処理クラス」の依存度が強くなってしまい、汎用性に 乏しいですし、その処理を他のプロジェクトで使いまわすときにも都合が悪くなります。 そのクラスが、どこから呼び出されるのかは、事前には分からないわけですから。
そこで、処理クラス側が常に同じメソッドを呼ぶのではなく、依頼側から処理クラスに対して 『ユーザがクリックしたら、私の「このメソッド」を実行して下さい』 『計算途中でエラーが発生したら、私の「このメソッド」を呼び出して進捗を報告してください』 『計算が完了したら、最後に、私の「このメソッド」を実行して、処理の完了を通知してください』 などといった依頼をする形にして、使い回しが利くようにしてみます。
ではこのとき、呼び出してもらう「このメソッド」を、どのようにして渡すのが良いでしょうか。
-------------- 実装案1) 「この関数」を示す「メソッド名文字列」と、それを実装したオブジェクトを渡す方法。
' 依頼側 obj.Foo(Me, "MyMethod") '← Me に Public Sub MyMethod() があるとして。
' クラス側の実装 Public Sub Foo(ByVal target As Object, ByVal methodName As String) : ' それらを、CallByName を使って呼び出す。 CallByName(target, methodName, CallType.Method) : End Sub --------------
これなら、処理クラスが、特定の依頼者に依存するという問題を軽減することができます。
でもこの方法だと、渡すべきメソッド名を間違えていても、コンパイル時には発覚しません。 それに、CallByName を使うが故に、「この関数」を Private にすることができませんね。
そこで、別案。
-------------- 実装案2) 処理させる関数を、あるインターフェイスのメソッドとして実装させておき、 そのインターフェイスを実装したクラスを渡す方法。
' クラス側の実装 Public Sub Foo(ByVal target As ISample) : target.SampleMethod() : End Sub -------------- 実装案3) 「この関数」を表すデリゲートのインスタンスを渡す方法。
' クラス側の実装 Public Sub Foo(ByVal target As SampleDelegate) : target() : End Sub ---------
これらの方法では、コンパイル解決もできますし、Private メソッドへの実装も可能です。
> 「関数ポインタ」という表現で紹介されてるところも見かけるけど、その割りに、 あるいは、「JavaScript でいうところの、Function オブジェクトや匿名メソッド」とか 「VBScript でいうところの、GetRef関数」などと表現されることもあるようで。
で、デリゲートを関数ポインタのように使う事はできますが、両者は異なるものです。 実際、デリゲートの方が高機能ですしね。 (VB6 時代の AddressOf は、まさに関数ポインタでしたけれども)
|