実際には、Observer パターンの実装は、再入可能性による悪い動作をどのように回避するのでしょうか?
「悪い動作」を明確にするために、パターン内のサブジェクトがメソッド MethodA() と MethodB()、イベント OnMethodA() と OnMethodB()、および 1 つ以上のオブザーバーをシングルスレッドの同期実装で持つ状況を考えてみましょう。
- Subject.MethodA() が呼び出され、
- Subject は MethodA() に対して行うことを行い、次にすべての Observer に対して OnMethodA() を呼び出します。
- Observer1 は OnMethodA() イベントを取得し、Subject.MethodB() を呼び出します。
- Subject は MethodB() に対して行うことを行い、次にすべての Observer に対して OnMethodB() を呼び出します。
この時点で、まだ OnMethodA() の通知の途中ですが、すべてのオブザーバーに対して OnMethodB() を呼び出しています。これは、リスト内の Observer1 の後のすべてのオブザーバーが、「OnMethodA()」の前に「OnMethodB()」を参照することを意味します。これは悪い動作です。
- Observer2 (Observer1 について何も知らない開発者によって作成された) は、OnMethodB() イベントを取得し、Subject.MethodA() を呼び出します。
- …永遠に。Subject.MethodA() -> Observer.OnMethodA() -> Subject.MethodB() -> Observer.OnMethodB() -> Subject.MethodA() -> など…</li>
ここで、スタックをオーバーフローさせます。それは悪い振る舞いです。
最初から非同期のキューベースの通知を使用して設計した場合、または通知中に Subject への呼び出しで例外をスローした場合は、これを回避できます。これは非常に簡単に理解できます。私を悩ませているのは、これがパターンを実装する際のベスト (または実際には唯一の) プラクティスとして言及されているのをほとんど見たことがないことです。「オブザーバーパターンリエントラント」をグーグルで検索するには、すでに問題を認識している必要があります。その検索の結果は、パターンに関する本の警告ではなく、問題に遭遇した人だけのようです。
それで、私は何かを逃していますか? 実際には、Observer パターンの実装は、再入可能性による悪い動作をどのように回避しますか?