本文介绍了事件监听器的设计方法。事件监听器是经常可以遇到的一种设计模 式,即:当模块的一部分A在完成后需要通知其他的软件模块B,而等待通知的模块B在事先不需要采用轮询的方式来查看另一个模块A是否通知自己。
事件监听器是经常可以遇到的一种设计模式,一般用在这样一种场景下:当模块的一部分A在完成后需要通知其他的软件模块B,而等待通 知的模块B在事先不需要采用轮询的方式来查看另一个模块A是否通知自己。即,当某事件发生,则监听器立刻就知道了该事件。这种模式大量的应用在GUI设计 中,比如按钮的点击,状态栏上状态的改变等等。
笔记: 某个类实现监听器就是获得一个listener的引用(把实现了监听器接口的监听器对象set进类的属性里--注册监听器),在适当时机通过listener调用监听器里的方法。
接口的设计
我们需要一个对事件(event)的抽象,同样需要一个对监听器(listener)的抽象。我们可以把接口抽的很简单:
这个是事件源的接口,只需要提供一个可以获取事件类型的方法即可:
- package
listenerdemo.framework;
- /**
- * @author juntao.qiu
- */
- public
interface
EventListener {
/**
- * handle the event when it raise
- * @param event
- */
public
void
handleEvent(EventSource event);
- }
监听器接口,提供一个当事件发生后的处理方法即可:
- package
listenerdemo.framework;
- public
interface
EventSource {
public
final
int
EVENT_TIMEOUT =
1
;
public
final
int
EVENT_OVERFLOW =
2
;
/**
- * get an integer to identify a special event
- * @return
- */
public
int
getEventType();
- }
实例化事件
我们举一个实现了事件源接口(EventSource)的类TimeoutEvent 来说明如何使用事件监听器模型:
- package
listenerdemo;
- import
listenerdemo.framework.*;
- public
class
TimeOutEvent
implements
EventSource{
private
int
type;
public
TimeOutEvent(){
this
.type = EventSource.EVENT_TIMEOUT;;
- }
public
int
getEventType() {
return
this
.type;
- }
- }
这个事件的类型为EVENT_TIMEOUT, 当操作超时时触发该事件,我们假设这样一个场景:一个定时器T, 先设置这个定时器的时间为t,当t到时后,则触发一个超时事件,当然,事件是需要监听器来监听才有意义的。我们看看这个定时器的实现:
- package
listenerdemo;
- import
listenerdemo.framework.*;
- /**
- * @author juntao.qiu
- */
- public
class
Timer
extends
Thread{
private
EventListener listener;
private
int
sleepSeconds;
public
Timer(
int
seconds){
this
.sleepSeconds = seconds;
- }
public
void
setEventListener(EventListener listener){
this
.listener = listener;
- }
public
void
run(){
for
(
int
i = sleepSeconds;i>
0
;i--){
try
{
- Thread.sleep(
1000
);
- }
catch
(InterruptedException ex) {
- System.err.println(ex.getMessage());
- }
- }
- raiseTimeoutEvent();
//raise一个TimeOut事件给监听器
- }
private
void
raiseTimeoutEvent(){
this
.listener.handleEvent(
new
TimeOutEvent());
- }
- }
使用事件及其监听器
在类Tester的execute()方法中,我们先设置一个定时器,这个定时器初始化为3秒,设置好定时器后,程序进入一个 while(true)循环中,当定时器到时后,它会发送一个timeout事件给当前线程Tester,此时我们可以设置execute中的while 条件为false,退出死循环。流程很清晰了,我们来看看代码:
- package
listenerdemo;
- import
listenerdemo.framework.*;
- /**
- * @author juntao.qiu
- */
- public
class
EventListenerTester
implements
EventListener{
private
boolean
loop =
true
;
public
void
execute(){
- Timer timer =
new
Timer(
3
);
//初始化一个定时器
- timer.setEventListener(
this
);
//设置本类为监听器
- timer.start();
while
(loop){
try
{
- Thread.sleep(
1000
);
- System.out.println(
"still in while(true) loop"
);
- }
catch
(Exception e){
- System.err.println(e.getMessage());
- }
- }
- System.out.println(
"interupted by time out event"
);
- }
- //实现了EventListener接口
public
void
handleEvent(EventSource event) {
int
eType = event.getEventType();
switch
(eType){
//判断事件类型,我们可以有很多种的事件
case
EventSource.EVENT_TIMEOUT:
this
.loop =
false
;
break
;
case
EventSource.EVENT_OVERFLOW:
break
;
default
:
this
.loop =
true
;
break
;
- }
- }
public
static
void
main(String[] args){
- EventListenerTester tester =
new
EventListenerTester();
- tester.execute();
- }
- }
运行结果如下:
run:
still in while(true) loop
still in while(true) loop
still in while(true) loop
interupted by time out event
程序正 是按照预期的方式运行了,当然,为了说明主要问题,我们的事件,对事件的处理,监听器的接口都尽可能的保持简单。如果想要完成更复杂的功能,可以参考文章 中的方法自行扩充,但是大概流程文中都已经说到。