设计模式系列<Java实现>-监听者模式

监听者模式

说到监听者,不得不提一下回调函数这个东西,回调这个词见得最多的应该是在JavaScript语言中,比如常见的Ajax技术,$ajax中的success就是一个回调函数,函数的具体实现需要程序员自己实现,而至于函数何时被调度则取决于请求的成功与否。

回调函数多用于异步的场景,可以最大的提升程序的响应速度,克服了BIO相应的缺点。举个生活中的例子,临近期末,Steve要去学校打印店打印资料,恰逢人流高峰期,看着前面长长的队伍,他只好默默的排到队伍的最后,煎熬的等待着,对应到我们这,这是一个阻塞的过程,而异步是怎样的呢,异步在这里就相当于打印店并不需要排长长的队伍,去打印只需要将资料放在老板那里,然后给老板登记个联系方式,之后Steve便可以立马去干其他的事情,不必一直傻傻的等下去,等到资料打印好后老板自然会电话通知你去取资料,这个通知的动作就是一个回调。

其实监听者模式和回调有着异曲同工之妙,首先这里会涉及到三个对象。

  • 事件源 (事件发生的源头,作为被监听的对象)
  • 事件对象 (事件本身,用于包装事件源,提供事件的属性等)
  • 监听器 (事件发生后需要执行的动作,即回调函数)

现在我们来实现一个最容易理解的Button(按钮)控件,并实现他的Click(单击)事件。

首先定义一个事件源Button

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Button {
private List<ClickListener> eventListeners = new ArrayList<>();

public void addListener(ClickListener eventListener) {
eventListeners.add(eventListener);
}

private void notifyListener(ClickEvent eventObject) {
Iterator<ClickListener> it = eventListeners.iterator();
if (it.hasNext()) {
ClickListener clickListener = it.next();
clickListener.handleEvent(eventObject);
}
}

public void click() {
ClickEvent clickEvent = new ClickEvent(this);
System.out.println("按钮被点击");
notifyListener(clickEvent);
}
}

之后继承JDK提供的EventObject类来定义我们自己的事件对象

1
2
3
4
5
class ClickEvent extends EventObject {
public ClickEvent(Object source) {
super(source);
}
}

最后继承JDK提供的EventListener接口来规定自己的监听器接口

1
2
3
interface ClickListener extends EventListener {
void handleEvent(ClickEvent eventObject);
}

主函数测试

1
2
3
4
5
6
7
8
9
10
public class Main {

public static void main(String[] args) {
Button button = new Button();
// 这里用了Lambda语法,其实就是new了一个实现了ClickListener接口的类
// 我们需要在按钮被按下后弹出对话框
button.addListener((x) -> System.out.println("弹出对话框"));
button.click();
}
}

里面的函数式写法JDK1.8开始支持,我以后可能也会写相关的总结,可以先不管。来看下输出结果吧

按钮被点击

弹出对话框

完美,按钮被成功按下,并且也弹出了我们想要的对话框。

写在最后

1.能不去继承JDK的类和接口吗?

能!能!能!这样写只是为了规范考虑,因为大佬都这么写,不这样写你会被骂low

2.还没想到…

文章作者: Shawn Qin
文章链接: https://qinshuang1998.github.io/2019/02/03/design-pattern-01/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Shawn's Blog