Java如何实现事件?
C#的事件
相信很多学过C#的同学,都听过事件这个概念。
它是基于一种订阅者模式的编程模式。而C#的事件,都是基于委托的。
而委托其实就是对象化的函数。
在其他大部分语言中,也是支持的这个概念的,只是叫法不同而已。在C++中叫做函数指针,在JavaScript中函数本身就是一个对象。
事件的原理
事件也就是一个可能在未知的时候发生的事情,这件事情如果我们需要对它进行一个关注,比如我们关心明天会不会下雨,以便于我们在下雨的时候,将伞带在身上。 这个时候下雨就是我们关心的事件,将伞带在身上,就是我们对这个事件的处理。
这是站在订阅者的角度,去看这个事情,它真的非常简单。我们一旦订阅了这个事件,那么我们对事件的处理就会自动触发。
那么如果我们想实现这个事件机制,应该怎么做呢?
首先,我们的事件是需要在合适的时候被触发的。这个触发的时机,订阅者们根本不会关心。而事件的拥有者会处理这个事情,比如前面说的下雨,我们关注天气的人不会具体什么时候下雨,气象台的人才会去关心,并且是由他们来通知我们,下雨这个事情发生了。
第二,我们事件本身,需要保存一份清单,我们需要知道哪些人订阅了这个事件。
就像送报纸,一个邮递员手上必然有一份清单,记录了那些人订阅了这份报纸,不然这报纸不就送丢了吗。
第三,我们的事件必须可以被订阅。就比如一个人想去订购一份报纸,它得去打电话告诉报刊社,但是这个报刊社根本就像不存在一样,找不到它的电话号码,那就根本订阅不了了。
Java实现
Java是没指针这个概念的,但是可以通过接口。
并且在Java8新增了lambda表达式和非常酷炫的函数接口(和委托非常像)。
前面说的条件,已经足够说明事情了,很显然,我们需要两个函数,一个函数用来处理订阅,这个函数会被订阅者调用。一个函数用来让这个事件发生,这个函数会被事件的拥有者在合适的时候调用。然后需要一个列表,用来存储所有对这个事件的订阅。
下面就上代码吧:
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
//事件基类,定义了订阅,触发,取消订阅等方法。
public abstract class Event<T> {
protected Event(Class c) {
Annotation annotations = c.getAnnotation(FunctionalInterface.class);
if (annotations == null) {
throw new IllegalArgumentException("Type of Argument must be a FunctionalInterface");
}
}
//用于保存所有事件处理的函数
protected final List<T> funcList = new ArrayList<>();
public void subscribe(T func) {
this.funcList.add(func);
}
public void unSubscribe(T func) {
this.funcList.remove(func);
}
import java.util.function.Consumer;
//具体事件类,继承于Event,需要具体指明订阅者函数的类型(在C#中就是指明用什么委托来处理这个事件)。
public class MyEvent<T> extends Event<Consumer<T>> {
public MyEvent() {
super(Consumer.class);
}
public void invoke(T arg) {
for (Consumer<T> trFunction : this.funcList) {
trFunction.accept(arg);
}
}
}
下面来用一下
import demo.main.MyEvent;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
Main main = new Main();
//定义事件处理函数
Consumer consumer = x ->
System.out.println("MyEvent is Invoke,the param is " + x);
main.myEvent.subscribe(consumer);
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
main.myEvent.invoke(100);
}
};
timer.schedule(task, 10000);
}
MyEvent myEvent = new MyEvent();
}
在10000毫秒后,事件发生了。
输出结果:
Java的事件写起来,确实没有Js和C#那么方便,我觉得主要是
官方对事件,并没有像C#那样提供编译器层面的支持。
还有就是Java的泛型擦除,这样使用,会导致IDE警告,用起来有点不爽。
- 0
- 0
-
分享