2013-03-03 84 views
4

實際上,觀察者模式的實現如何避免由於重入導致的不良行爲?觀察者模式:避免不良的重入行爲?

爲了闡明「不良行爲」,考慮模式中的Subject有單線程方法MethodA()和MethodB(),事件OnMethodA()和OnMethodB()以及一個或多個Observers的情況同步實現:

  • Subject.MethodA()被調用,
  • 主題做什麼它爲methodA(),然後調用OnMethodA()爲所有的觀察員,
  • Observer1得到OnMethodA( )事件,並調用Subject.MethodB(),
  • 該主題做什麼它的方法b(),那麼對於所有的觀察員呼籲OnMethodB(),

在這一點上,我們稱之爲OnMethodB()所有觀察員,儘管我們仍然在通知中的中間爲OnMethodA()。這意味着列表中的Observer1之後的任何觀察者都將在「OnMethodA()」之前看到「OnMethodB()」 - 這是不好的行爲。

  • Observer2(由誰不知道什麼Observer1一個開發者編寫)得到OnMethodB()事件,並調用Subject.MethodA(),
  • ...永遠。 Subject.MethodA() - > Observer.OnMethodA() - > Subject.MethodB() - > Observer.OnMethodB() - > Subject.MethodA() - >等...

現在你要溢出堆棧。那是不好的行爲。

如果你已經設計了異步,基於隊列的通知,從一開始,或通知期間拋出的通話主題的例外,就可以避免這一點,這是很容易理解。有什麼困擾我的是,我幾乎從來沒有把這種做法看作是實施該模式的最佳(或者真的,唯一的)做法。你必須已經意識到谷歌「觀察者模式可重入」的問題,並且搜索結果似乎只是遇到問題的人,而不是關於模式的書中的警告。

所以我錯過了什麼? 在實踐中,Observer模式的實現如何避免由於重入導致的不良行爲?

回答

0

好吧,我從來沒有聽說過這個問題有可觀察的模式之前,所以+1了點。在另一方面你爲什麼不看的Java是如何通過ObserverObservable實現在java.util package這種模式,另一個值得注意的是,將會發生,因爲這種模式的使用不當的實際應用這個問題,看看這些Gotchas從觀察者模式的馬丁福勒。

1

至於避免重入,一個「修復」是設置一個標誌isResponding,isUpdating,無論如何。檢查它以避免重入。附:使它volatile

我是不是聲稱這是一個優雅或甚至是一個很好的解決方案。但有時候這是一條路。

0

這個關於無限遞歸的問題是一個重要的問題,需要注意觀察者模式,並在GUI應用程序中使用模型視圖控制器(MVC)模式。在之前的工作中,我嘗試過使用標誌的方法來防止這種情況,但是我發現使用標誌增加了複雜性,並且有時不能按預期工作。

我發現爲我工作並且自信地使用了超過五年的解決方案是通過確保代碼更新視圖的狀態以響應模型來打破控制器中的循環更改事件,您沒有觀察通過更改視圖生成的事件。如果在你的情況下這是不可能的,那麼使用國旗是你最好的選擇。

一個簡單的例子就是一個模型,其數據爲單個字符串,視圖爲文本字段,它們之間爲控制器對象。如果用戶修改字符串,它會通知控制器,告訴模型更新其字符串。型號更改通知控制器更新文本字段。這是你必須小心的地方。控制器需要能夠區分由於用戶操作而生成的視圖中的事件,或者自己更新視圖內容。在某些情況下,您只需從視圖中選擇合適的事件進行監聽,而在其他情況下,您需要讓控制器跟蹤它是否正在修改視圖。

在這個特定的例子中,解決方案是讓控制器在完成編輯時從文本字段監聽事件,而不是在文本字段中的文本被修改時監聽。