オブザーバーパターンに対するデリゲートパターンの利点は何ですか?


9

デリゲートパターン、1つのオブジェクトのみが直接、別のオブジェクトのイベントに耳を傾けることができます。でオブザーバーパターン、オブジェクトの任意の数は、特定のオブジェクトのイベントに耳を傾けることができます。他のオブジェクトにイベントを通知する必要があるクラスを設計するときに、オブザーバーパターンよりもデリゲートパターンを使用するのはなぜですか?オブザーバーパターンはより柔軟であると思います。現在、オブザーバーは1人しかいませんが、将来の設計では複数のオブザーバーが必要になる場合があります。


4
「デリゲートパターン」とはどういう意味ですか?.netのデリゲートのようなものについて話している場合、好きなだけサブスクライバーを持つことができます。
CodesInChaos

ココアに重点を置いていますが、関連:NSNotificationCenter対委任(プロトコルを使用)?
mouviciel 2014年

回答:


7

デリゲートパターン自体はありません。私はあなたが委任パターンを意味すると仮定します。

私が理解しているように、これらは互いに完全に逆であり、さまざまな目的で使用されています。

通常、オブザーバーパターンでは、任意の数のオブザーバーオブジェクトが2番目のオブジェクトのイベントをリッスンし、そのイベントに作用します。2番目のオブジェクトはリスナーを認識していません。彼らに声をかけるだけです。

デリゲートオブジェクトは、デリゲートで直接メソッドを呼び出す2番目のオブジェクトに渡されます。そしてそこにあなたが探している利点があります。単一のメッセージを複数のリスナーに送信するのではなく、単一のオブジェクトを(ある時点で)完全に制御します。Inversion of Controlも参照してください。


6

あなたは物事を間違って見ています。オブザーバーは、特定のイベントが発生したことを確認します。それはそれに影響を与えません、またはそれを所有しません。デリゲート特定のイベントを処理し、デリゲーターがイベントへのインターフェイスを所有している場合でも、ハンドラーの所有権を持ちます。


1
デリゲートは、実際にはイベントのオブザーバーにすぎません。デリゲートは何も「処理」する必要はありません。安全に何もすることができず、イベントをトリガーしたインスタンスには影響しません(または少なくとも影響しません)。
Marjan Venema

5
@MarjanVenema -オブジェクトAがされていない場合、委任オブジェクトBへのイベントの責任を、あなたは委任パターンを使用していない:あなたが唯一のオブザーバーでオブザーバーパターンを使用しています。
Telastyn

はい、それは私が考えていたものです。「OnWhatever」イベントのサブスクライバーが使用するイベントシグネチャタイプであると委任されていることを理解しました。どうやらC#のデリゲートは、たとえばDelphiのように単一サブスクライバーではありません。
Marjan Venema

@Marjan Venema「デリゲートは、実際にはイベントのオブザーバーにすぎません。」-それはあなたが話している言語に依存します。Objective Cでは、一部のデリゲート(たとえば、データデリゲート)がデータの提供を担当し、データデリゲートがないオブジェクトには、表示するデータがありません。このような場合、何かを観察するだけの行為とは異なり、委任が発生します。
occulus

1
@occulus:説明してくれてありがとう。言語が用語に同意できないのは残念です...言語にとらわれない方法でのプログラミングについて話すことは、人々が同じ単語に対して異なることを理解するときに少し難しくなります。
Marjan Venema

4

それはいくつかのトレードオフの問題です。

トレードオフ:

  • 柔軟性(n> 1のデリゲート/オブザーバーを持つという点で)
  • メッセージを送信するコスト
  • レジリエンス(代理人/オブザーバーの利用不可を維持する能力)
  • 使いやすさ

デリゲートパターン:

  • あまり柔軟ではありません-複数のデリゲートを追加することはできません(何らかの形の「マルチデリゲート」、つまりオブザーバーパターンを意味します)
  • メッセージの送信は安価です。O(1)-他の関数またはメソッドを呼び出すのと同じコスト(ルックアップ、メッセージキュー、または他のインフラストラクチャは不要)
  • 通常、弾力性はありません-デリゲートが存在し、作業の一部を行うことが期待されます。つまり、デリゲートが既知でない場合、送信者は失敗する傾向があります。
  • 把握しやすく、実装が簡単

オブザーバーパターン:

  • 非常に柔軟-n> 1オブザーバーを追加することが設計上期待されます
  • メッセージの送信には、オブザーバーの数O(n)によって暗示されるコストがあります。つまり、n人のオブザーバーはn時間とメッセージを受け取ります(少なくとも単純な実装では)
  • 通常は回復力があります-オブザーバーは通常、送信者の一部に対して作業を行うことは想定されていません。それは、送信者が影響を受けないオブザーバーがいない場合でも
  • 特にオブザーバーがメッセージに反応することが期待されている場合、把握するのがかなり複雑になる可能性があります(順序は重要ですか?、どのオブザーバーがどのように応答しますか?)

1

私が理解しているように、デリゲートパターンは、Delphiなどの他の言語ではイベントハンドラーメカニズムとして知られています。このように、それは単にオブザーバーパターンの実装であり、大きな制限があります。一度に1つのリスナーのみです。

イベントハンドラーまたはデリゲートの欠点は明らかです。オブザーバーが1つだけです。

利点はそれほど明白ではありません。パフォーマンスです。オブザーバーパターンを使用すると、多くのオブザーバーを追加できます。オブザーバーに通知する必要があるイベントが発生した場合、オブザーバーを列挙し、それぞれに通知を送信する必要があります。これは、特に通知を必要とするイベントの数が非常に多い場合に、観察されたインスタンスをすぐに停止させる可能性があります。


え?C#デリゲートは、変数型としてのメソッドのシグネチャです(たとえば、int (*my_int_f)(int)C と同等)。構造体/列挙型のように機能させることで、これを理解しやすくしたといつも思っていました。イベントは、単一のデリゲートシグネチャを使用した、リスナーの柔軟な配列のフックです。あなたは可能性がありますが、言語はあなたのために簡単にそれを作っている(私は非常に異なっているOP意味委任パターンを、仮定理由である)イベントなしでそれを行います。
pdr

うーん。まだC#に精通していません。私はデリゲートが、たとえばDelphiの「OnWhatever」イベントで使用されるイベントシグネチャタイプと同等であることを理解しました。では、C#イベントは複数のリスナーによってサブスクライブできますか?
Marjan Venema

一般的なAction <T>はデリゲートです。イベントとは何の関係もなく、渡される変数です。そして、はい、複数のリスナーが1つのイベントをリッスンできます。
pdr

わかりました。ありがとうございます。C#のリファレンスを取り除き、イベントメカニズムに重点を置きました。
Marjan Venema

1

これは古い投稿ですが、いずれにしても、他の回答ではどちらのパターンを使用した場合にも何が起こっているかを扱っていないので、チャイムを使って説明します。

委任とオブザーバーのしくみ

委任を使用すると、委任者は、潜在的なイベントのソースが作成された瞬間に、特定のイベントに誰が応答するかを正確に選択します。このリスナーは単一のオブザーバーと考えることができます。オブザーバーパターンの場合、オブザーバーは、気になるときはいつでも、誰が監視しているかを選択します。したがって、オブザーバーと委任では依存関係が逆になります。オブザーバーパターンでは、新聞と購読者をオブザーバーとして考えます。オブザーバーは、関係が作成されるタイミングを制御します。代表団と一緒に、従業員と雇用者について考えてください。雇用主は、関係が作成される時期と、特定のイベントの担当者を正確に管理します。従業員は自分が取り組んでいるタスクを選ぶことはできません...一般的に。

委任には1人のオブザーバーがいる可能性があると主張する人もいますが、2人の真の違いは、イベント処理の割り当て方法にあると思います。イベントのデリゲートレジスタは表示されません。イベントが発生し、委任者がイベントに対してパブリックメソッドを呼び出すまで、イベントが処理されることさえわかりません。

委任の利点

このパターンは非常に厳格であり、ほとんどのregidの設計では、より単純で一般的に堅牢です。潜在的なイベントのソースを初期化するときに、イベントハンドラーを事前に宣言する必要があります。誰かが交通を誘導する必要がある場合、あなたは通りを開く前に交通ディレクターを割り当てます。オブザーバーの場合は、交通警官に、トラフィックが気になるときにいつトラフィックを転送するかを選択させます。

委任の短所

この設計の欠点は、柔軟性がないことです。新聞を購読するためのコードを実装している場合、新聞/委任者は、作成された2番目のニュース記事を誰が読むことができるかを正確に特定する必要があります。オブザーバーパターンを使用すると、後でいつでも登録でき、新聞は新しい人物が登録したことを知るだけで済みます。

委任を選択するのはいつですか?

特定のオブザーバーが確実に必要で、誰を監視するかを変更する理由がない場合は、委任パターンの厳密な設計が有益です。

たとえば、特定のエラーのポップアップの作成を処理するクラス/オブジェクトが必要です。実行時に特定のエラーを処理するユーザーを切り替える必要がある理由は多くありません。そのため、「メモリ不足」エラーを単一のエンティティに委任することは理にかなっています。潜在的なハンドラーの配列を作成してから、それらのハンドラーに「メモリ不足」エラーを登録させることは、あまり意味がありません。これは、この状況でオブザーバーパターンを使用する例です。実行時に、呼び出されるメソッドや変数イベントで呼び出される「デリゲート」を変更したい場合がありますが、実行時に特定のイベントのイベントハンドラーをスワップアウトすることは正常ではありません。

オブザーバーパターンで行うのと同じようにデリゲートを交換することは不可能ではなく、複雑です。現実の世界では、新しい警備員がトラフィックを処理するように、交通警官を入れ替えたいと思うでしょう。より良い設計は、元の代理人を警察署ではなく一人の警察官にするであろうと主張することができますが、私は余談です...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.