3

GC 対応言語では、オブザーバーがサブジェクトのイベントをサブスクライブすると、実際にはサブジェクトはオブザーバーの参照を取得します。

したがって、オブザーバーをドロップする前に、まずサブスクライブを解除する必要があります。それ以外の場合は、まだサブジェクトによって参照されているため、ガベージ コレクションされることはありません。

通常、3 つの解決策があります。

  1. 手動で購読を解除する
  2. 弱参照。

どちらも他の問題を引き起こします。

そのため、通常はオブザーバー パターンを使用するのは好きではありませんが、その代わりになるものはまだ見つかりません。

つまり、このパターンは非常に自然な方法で物事を説明しているため、これ以上のものはほとんど見つかりません。

あなたはそれについてどう思いますか?

4

3 に答える 3

1

finalize()このシナリオでは、Java で使用できます。一部の外部システムが影響を受けるため、リソース (DB 接続など) を解放する必要finalize()ある場合、これは悪い考えです。あなたの場合、オブザーバーをインストールしたオブジェクトは、アプリの実行時にGCされてから呼び出され、オブザーバーのサブスクライブを解除できます。finalize()

あなたが望むものとは正確には異なりますが、誰かが「今すぐ購読を解除しても大丈夫」と判断する必要があります. これは、サブジェクトが離れたときに発生するか (ただし、すべてのオブザーバーが既に殺されているはずです)、またはオブザーバーをインストールしたオブジェクトのいずれかです。

アプリが予期せず終了しfinalize()た場合でも、この場合は呼び出されなくても問題ありません。

于 2009-11-11T16:50:11.307 に答える
0

観察可能なものがどのくらいの頻度で変化するかを数えるオブジェクトのシナリオを考えてみましょう。オブジェクトへの参照には 2 つのタイプがあります。(1) カウントに関心のあるエンティティによるもの。(2) カウントに実際には関心がないが、カウントを更新する必要がある観察可能なものによって使用されるもの。カウントに関心のあるエンティティは、カウントを管理するオブジェクトへの参照を保持するオブジェクトへの参照を保持する必要があります。カウントを更新する必要があるが、実際には関心がないエンティティは、2 番目のオブジェクトへの参照を保持する必要があります。

最初のオブジェクトがファイナライザーを保持している場合、オブジェクトがスコープ外に出たときにファイナライザーが起動されます。これにより、2 番目のオブジェクトが登録解除される可能性がありますが、直接登録解除するべきではありません。サブスクリプションを解除するには、おそらくロックを取得する必要があり、ファイナライザーはロックを待機するべきではありません。代わりに、最初のオブジェクトのファイナライザーは、おそらく Interlocked.CompareExchange を使用して維持されるリンク リストにそのオブジェクトを追加し、他のスレッドが定期的にそのリストをポーリングして、サブスクリプション解除が必要なオブジェクトを探す必要があります。

注: 最初のオブジェクトが 2 番目のオブジェクトへの参照を保持している場合、最初のオブジェクトのファイナライザーが実行されたときに後者が存在することが保証されますが、特定の状態にあることは保証されません。クリーンアップ スレッドは、サブスクライブ解除以外に何もしようとしないでください。

于 2010-09-30T15:55:34.347 に答える
0

オブザーバーを削除する場合は、まずサブスクライブを解除してパブリッシャーに通知する必要があります。そうしないと、イベントの送信が試行され、記述方法によっては、アプリがクラッシュしたり、エラーを静かに無視したり、オブザーバーを削除したりする可能性があります。ただし、何かを開いた場合は閉じます。購読する場合は、購読を解除してください。

あなたが購読を解除していないという事実は悪い設計です、IMO. 不適切な実装をパターンのせいにしないでください。

オブザーバー パターンはうまく機能しますが、いくつかの問題を軽減したい場合は、実装に AOP を使用できます

于 2009-11-11T16:51:03.053 に答える