Java中的事件处理

紧接着上一篇说,学习观察者模式的时候看到了这个事件处理机制,大体浏览了一下就是用的观察者模式嘛,并且是惊人的相似,既然这样那就顺便写写啦

Java 的事件机制中一共设计到3个角色,分别是:事件源、事件对象、事件监听器
事件源上发生某操作的时候,会调用事件监听器里的相应的监听方法,并在调用这个方法的时候把事件对象传递过去,事件监听器由开发人员编写
所以在事件监听器中可以通过事件对象拿到相应的事件源

举个栗子,比如把一个窗口当作是事件源,当点击这个窗口上的某个按钮的时候就相当于触发了一个事件,然后会被事件监听器捕获到,交给相应的方法去处理(会携带事件对象)

实现步骤

事件源

首先定义/确定一个事件源,我呢,就继续厚颜无耻的改造下前面的代码用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class StandardLoli {
private String name = "佳芷";
private LoliListeners listeners;

// 当事件触发的时候通知相应的监听器
public void speak(String name) {
System.out.println("大哥哥" + name + "快来呀!!");

if (listeners != null) {
Event event = new Event(this);
listeners.speakListeners(event);
}
}

public void hug() {
System.out.println("(づ。◕‿‿◕。)づ");
if (listeners != null) {
Event event = new Event(this);
listeners.hugListeners(event);
}
}

public String getName() {
return name;
}

// 提供一个注册监听器的方法,由事件源对象调用
public void registerListeners(LoliListeners listeners) {
this.listeners = listeners;
}
}

当然是允许注册多个监听器的,那就要定义一个集合来存储了,和前面的观察者模式一样,我就简单起见,只写了一个的情况

事件对象

我认为事件对象就是用于传递对象或者说是数据的,当事件触发的时候通知事件监听器的时候总是会带点东西过去吧….最起码也得把自己带过去啊

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Event {
private StandardLoli mStandardLoli;

public Event() {}

public Event(StandardLoli standardLoli) {
mStandardLoli = standardLoli;
}

public StandardLoli getStandardLoli() {
return mStandardLoli;
}
}

我这里还真的就只带了自己过去,或者可以加一个 status 的属性

事件监听器

与其相关的有两个类,一个是接口,一个是它的实现类;接口的作用嘛,除了规范主要就是用来在事件源中调用未来的方法的!这个说法很好啊,因为事件源中触发事件后调用监听器的方法时确实不知道你是怎么实现的

1
2
3
4
5
public interface LoliListeners {
// 一个监听方法对应一个事件源中的需要被监听方法
void speakListeners(Event event);
void hugListeners(Event event);
}

废话不说,接着是它的实现类,也就是真正的事件监听器

1
2
3
4
5
6
7
8
9
10
11
12
public class MyListeners implements LoliListeners {
@Override
public void speakListeners(Event event) {
StandardLoli loli = event.getStandardLoli();
System.out.println(loli.getName() + "我来了!!");
}

@Override
public void hugListeners(Event event) {
System.out.println("抱抱..");
}
}

我都感觉我的命名和方法有些丧心病狂…..

测试类

最后一步就是进行测试了,也就是实际用的时候应该怎么用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
// 事件源
StandardLoli loli = new StandardLoli();

// 注册监听器
loli.registerListeners(new MyListeners());

// test
loli.speak("bfchengnuo");
System.out.println("----------------");
loli.hug();
}
}

使用Java默认实现

巧了,在 Java 中的 util 包中也提供了相关的类和接口,但是我感觉吧,比较鸡助啊,也许是我还没有领会到其中的精髓吧,那就再把上面的代码改把改把吧,先来看看 Java 给提供了那些东西:

  • public interface EventListener
    所有事件监听器接口必须扩展的标记接口
  • public class EventObject extends Object implements Serializable
    所有事件状态对象都将从其派生的根类。 所有 Event 在构造时都引用了对象 “source”,在逻辑上认为该对象是最初发生有关 Event 的对象。

事件对象

这次从事件对象写起,必须继承 EventObject 类,这样就不用定义保存事件源的对象了,此外只是定义了一个 status 的属性而已

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Event extends EventObject {
private String status;

/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public Event(Object source) {
super(source);
}

public Event(Object source, String status) {
super(source);
this.status = status;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}
}

至于继承的作用,应该也看出来了,就是那个构造方法

监听接口

是的,是定义一个接口,和上面的类似,只不过这个接口要继承 EventListener ,这是一个标记接口,就算打了标记,我目前认为没什么太大的作用,不过看看 API 手册又有另一番感慨…

1
2
3
4
5
public interface LoliListeners extends EventListener {
// 一个监听方法对应一个事件源中的需要被监听方法
void doSpeak(Event event);
void doHug(Event event);
}

监听接口的实现

和上面一样的套路,代码也基本一样,不多说,当然,可以定义多个实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyListeners implements LoliListeners {
@Override
public void doSpeak(Event event) {
// 拿到事件源对象
StandardLoli loli = (StandardLoli) event.getSource();
System.out.println(loli.getName() + "我来了!!");
}

@Override
public void doHug(Event event) {
String status = event.getStatus();
System.out.println("抱抱,状态" + status);
}
}

其他

除了上面的类,还需要一个 事件源对象和测试的类,这个两个完全可以照搬前面的代码,都不用改的

所以,使用 Java 的默认实现我也没感觉有多大的好处,代码也没少些嘛,也许是我功底不够理解不到,等我理解到了再回来写上哈

完整测试代码在 Github

EventListener 接口,这是由几十个其他接口扩展的 Java API,你可以使用一个标记接口来建立一组接口的父接口。
例如:当一个接口继承了 EventListener 接口,Java 虚拟机 (JVM) 就知道该接口将要被用于一个事件的代理方案。

喜欢就请我吃包辣条吧!

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~