3

オブザーバーパターンは誰もが知っています。状態の変化をオブザーバーのリストに通知して更新できるサブジェクトがあります。ここで、観察したいサブジェクトがコンテナーであり、コンテナー自体、つまり要素の追加と削除、および含まれている要素、つまりコンテナー要素の状態の更新を観察したいとします。

コンテナに大量のオブジェクトを格納するときに要素の挿入と削除が高速になるように、更新メカニズムをどのように実装しますか?特に、

  • オブザーバーのローカルコピーで同じタイプのコンテナーを使用しますか?
  • オブザーバーが使用すべきコンテナの賢い選択はありますか?(たとえば、リンクリストを監視している場合でも、常にバランスの取れたツリーを使用する方が速いでしょうか?)
  • イテレータを監視対象のコンテナに、イテレータをオブザーバのコンテナにすばやく変換するにはどうすればよいですか?(配列の場合は重要ですが、リンクリストの場合は難しいですか?)

たとえば、コンテナがリンクリストの場合、一定時間で要素を挿入できます。m人のオブザーバーがn個の要素を含むリストを反復処理する必要がある場合、更新にはO(n * m)の予想時間がかかります。

コンテナが配列の場合、要素の変更には一定の時間がかかり、要素のインデックスを渡す場合はm個のオブザーバーの更新にO(m)がかかり、オブザーバーが配列を反復処理する必要がある場合はO(n * m)がかかります。

それが役立つ場合は、次の例を検討してください。

例1.オペレーティングシステムを作成しています。観察したい主題は、ファイルシステムとそのファイルです。ビューは、ファイルエクスプローラー、インデクサー、およびその他のアプリケーションです。ファイルが追加、削除、または変更されたときにオブザーバーを更新したいとします。

例2.ニューヨークのサイズの都市を処理できるはずの名簿アプリケーションを作成しています。あなたが観察したい主題はあなたの記録の入れ物です(その住所、電話番号、電子メールを持っている人...)。オブザーバーはいくつかのビューであり、レコードを追加、削除、または変更すると自動的に更新されます。(53日に住んでいる人のリストを含む1つのビューと、姓がDoeである各人の地図上の別の描画ドットをイメージできます)。

ディレクトリサブツリー全体が削除された場合、または「53rdSt」が「DijkstraSt」に名前が変更された場合をどのように処理しますか?

4

2 に答える 2

4

どういうわけか、あなたはコンテナを主題に変えなければなりません。

ここでの主な問題は、変更に気付くための効率的な方法を見つけることです。ほとんどの場合、この問題が発生するのは、観察したいものが効率的な通知メカニズムを提供していないためです(おそらく、オブザーバーのデザインパターンが作成時に発明されなかったためです)

[編集]あなたは効率的な方法を求めているので、一般的な答えは「それは依存する」です。デザインパターンには、「万能」ソリューションはありません。これらは、問題へのアプローチ方法の一般的なルールです。特定の状況でルールを実装する必要がある方法は、その状況にあるときに解決するものです。

一般に、オブザーバーが小さな変更(つまり、属性の変更や要素の追加)を識別する必要がある場合、通知メッセージには、これを効率的に実行できる十分な情報が含まれている必要があります。したがって、大きなリストと挿入がある場合は、新しい要素のリストとインデックスに加えて「挿入されたアイテム」を送信します。

属性の変更に関しては、2つの解決策があります。1つは、リスト内のすべての要素にオブザーバーを追加することです。これは遅く、大量のRAMを必要とする可能性がありますが、同じリストに複数のタイプを追加できることを意味します。

または、「リストサービスのアイテムの変更」を行うこともできます。つまり、アイテムを直接変更することは禁止されており、常にサービスを使用する必要があります。その後、サービスはサブジェクトとして機能し、アイテム、古い値と変更された値、場合によってはリスト内のインデックスを使用して通知を送信できます。

[編集2]原則として、変更に関するできるだけ多くの情報を収集し、それをオブザーバーに渡します。しかし、それは本当にあなたの特定の問題に依存します。オブザーバーがリモートマシンに座っているとしましょう。この場合、リスト全体を送信する効率的な方法はありません。送信できるのは「アイテムXが挿入されました」だけで、それで十分です。コンテナに変更を通知する方法がない場合(たとえば、Webサイトの新しいWebページ)、コンテナはサイト全体を何度もトラバースして変更を見つけ、それをオブザーバーに効率的に伝える必要があります。

繰り返しますが、詳細は実際には特定の状況によって異なります。Googleは、1時間に数百万のWebページにアクセスする数千のWebスパイダーを実行しています。長い間、これは「効率的」でした(「唯一の方法」のように)。少し前に、「サイトマップ」プロトコルが実装されました。これにより、管理者は自分のWebサイトを、Googleのオブザーバーに変更について伝えることができるサブジェクトに変えることができます。

ですから、あなたがしなければならないことのより具体的な例を与えることができない限り、私はあなたにもっと具体的な答えを与えることはできません。デザインパターンでは、座って実際の問題を解決し、脳を活性化する必要があるポイントがあります。

[EDIT3]オブザーバーパターンの使用例をいくつか示します。

  • 多くのUIフレームワークは、このパターンを使用して、イベントを関係者に広めます。Qtには、すべてのサブジェクトが信号(送信する通知)を登録でき、オブザーバーがサブジェクトにアタッチできる中央スポットがあります。これは、すべての接続が管理される単一のスポットがあることを意味します。利点は、このデータ構造をすべてのオブジェクトに追加する必要がないことです。また、外部からのオブジェクト(Qt以外のオブジェクト)はメッセージを送受信できます。すべてが1つの場所にあるため、このデータ構造を簡単に最適化できます。欠点は、この構造が非常に大きくなる可能性があるため、関係するパーティが多い場合(完全に無関係なパーティであっても)、メッセージの送信に時間がかかることです。

  • Googleはサイトマッププロトコルを使用してウェブサイトをサブジェクトに変換します。これは、URLの最終変更時刻(HTTPGETではなくHTTPHEAD)のみを要求した場合でも、サイト全体を何度もトラバースするよりもはるかに効率的だからです。

  • WindowsおよびLinuxのファイルシステムは、新しいファイルまたは削除されたファイルについてアプリケーションに通知する通知を提供します。ここでの主な問題は、アプリケーションが実行されていないときにファイルが変更されたときに何が起こるかです。ディレクトリ内のファイルのチェックサムを維持するアプリがあるとします。もちろん、アプリがダウンしたときの変更について知りたいのですが、それは通知サービスが最後に送信した変更を追跡する必要があることを意味します。したがって、ここでは、アプリは起動時にツリー全体を読み取って、見逃した可能性のあるものを確認する必要があり、実行中に発生する変更にはオブザーバーパターンを使用する必要があります。

  • メールクライアントはオブザーバーです。最後に見た電子メールのIDをメールサーバーに通知し、サーバーは新しい電子メールについて通知します。

  • 複雑なモデルに多くの属性変更がある場合、通常、すべての変更を一元化して(1つの場所で実行する)、そこにオブザーバーをアタッチする(N個のオブザーバーをM個の個別のオブジェクトにアタッチする代わりに)唯一の方法です。この実装では、オブザーバーは「どこでも変更に興味がある」、「任意のサブジェクトのフィールドXの変更」、「サブジェクトYの変更」(通常、最後の変更は「フィールドの変更」を兼ねる)と言うことができます。サブジェクトYのX"-オブザーバーはフィールドへの変更を単に無視します!= X)。

于 2009-06-05T10:33:53.573 に答える
1

オブザーバーパターン自体を使ってみませんか?

被験者は、興味深いイベントについてオブザーバーに通知する必要があります。その後、オブザーバーはそれを利害関係者(加入者)に派遣しなければならない。

ここでは、主題の性質は重要ではありません。(私があなたの質問を間違って理解していない限り)。

于 2009-06-05T10:16:12.097 に答える