如何正确的使用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)一点,我们可能还甚至为此实现了测试驱动,并为严密的代码覆盖率和那根表示测试通过的小绿条而洋洋自得。而且不管怎么样,这不就是我从网上那些教程里面学来的写法吗?
那么问题来了:这个解决办法是有缺陷的……