如何正確的使用Java事件通知(1)
通過實現觀察者模式來提供 Java 事件通知(Java event notification)似乎不是件什么難事兒,但這過程中也很容易就掉進一些陷阱。本文介紹了我自己在各種情形下,不小心制造的一些常見錯誤。
Java 事件通知
讓我們從一個最簡單的 Java Bean 開始,它叫StateHolder,里面封裝了一個私有的 int 型屬性 state 和常見的訪問方法:
publicclassStateHolder?{
privateintstate;
publicintgetState()?{
returnstate;
}
publicvoidsetState(intstate?)?{
this.state?=?state;
}
}
現在假設我們決定要 Java bean 給已注冊的觀察者廣播一條 狀態已改變 事件。小菜一碟!!!定義一個最簡單的事件和監聽器簡直擼起袖子就來……
//?change?event?to?broadcast
publicclassStateEvent?{
publicfinalintoldState;
publicfinalintnewState;
StateEvent(?intoldState,intnewState?)?{
this.oldState?=?oldState;
this.newState?=?newState;
}
}
//?observer?interface
publicinterfaceStateListener?{
voidstateChanged(?StateEvent?event?);
}
接下來,我們需要在 StateHolder 的實例里注冊 StatListeners。
publicclassStateHolder?{
privatefinalSet?listeners?=newHashSet<>();
[...]
publicvoidaddStateListener(?StateListener?listener?)?{
listeners.add(?listener?);
}
publicvoidremoveStateListener(?StateListener?listener?)?{
listeners.remove(?listener?);
}
}
最后一個要點,需要調整一下StateHolder#setState這個方法,來確保每次狀態有變時發出的通知,都代表這個狀態真的相對于上次產生變化了:
publicvoidsetState(intstate?)?{
intoldState?=this.state;
this.state?=?state;
if(?oldState?!=?state?)?{
broadcast(?newStateEvent(?oldState,?state?)?);
}
}
privatevoidbroadcast(?StateEvent?stateEvent?)?{
for(?StateListener?listener?:?listeners?)?{
listener.stateChanged(?stateEvent?);
}
}
搞定了!要的就是這些。為了顯得專(zhuang)業(bi)一點,我們可能還甚至為此實現了測試驅動,并為嚴密的代碼覆蓋率和那根表示測試通過的小綠條而洋洋自得。而且不管怎么樣,這不就是我從網上那些教程里面學來的寫法嗎?
那么問題來了:這個解決辦法是有缺陷的……