最近在看Tomcat和Spring的源码,在启动的时候注册了各类Listener,事件触发的时候就执行,这里就用到了设计模式中的观察者模式。html
想一想之前在学Java的GUI编程的时候,就用到了事件的注册监听,而后写了一个小程序试验一下:
点击按钮触发相应的事件java
public class ButtonTest extends JFrame { ButtonTest() { JPanel panel = new JPanel(); JButton button1 = new JButton("按钮一"); JButton button2 = new JButton("按钮二"); panel.add(button1); panel.add(button2); this.getContentPane().add(panel); this.setVisible(true); button1.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("你按了按钮一"); } }); button2.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("你按了按钮二"); } }); } public static void main(String args[]) { new ButtonTest(); } }
嗯,写起来确实很简单,这是封装好的,咱们只须要注册事件,并实现对应的事件响应就好了。
那么这种神奇的模式是怎么实现的呢?
如下为个人分析过程。o(╯□╰)o
首先,咱们来回归本质,看看到底这种模式方便在哪儿。若是不这么作的话,咱们须要再每次点击按钮的代码里面把响应的内容加上,若是有一千个事件响应,咱们须要把这一千个响应都写到点击按钮这个方法里面,Oh!!MyGod!太麻烦了!
若是忘掉设计模式,咱们想一想这种事情应该怎么作呢?
咱们须要把这一千个响应管理起来,而后在事件触发的时候,把这些响应统一调用,不就好了?问题来了...
1.如何管理起来?
2.每一个响应都不同,每次写响应的时候都须要去点击事件那里加一段,改动之前的代码,此乃编程之大忌,耦合度过高
想一想回答,
1.把每个响应都经过一个响应链来管理,触发事件时,遍历这个响应链,作出响应。
2.能够定义一个接口,在响应的地方传入该接口,调用接口的方法。这样,每次须要响应的时候,实现该接口,传入具体响应的对象,这样咱们就只用关心如何响应了,不用关心如何去调用响应的办法。
晕了晕了晕了……
来看看Java中的事件处理机制是如何实现的吧!编程
来自维基百科的结构图:
图看看就行。
场景:按下开关,灯作出的响应。
1.定义事件对象小程序
/** * 事件对象。继承EventObject * Created by HuangYQ on 2016/5/31. */ public class SwitchEvent extends EventObject { private String switchState; //表示开关的状态 public SwitchEvent(Switch source, String switchState) { super(source); this.switchState = switchState; } public void setSwitchState(String switchState) { this.switchState = switchState; } public String getSwitchState() { return switchState; } }
2.定义事件监听接口设计模式
/** * 事件监听接口 * Created by HuangYQ on 2016/5/31. */ public interface SwitchListener extends EventListener { public void handleEvent(SwitchEvent switchEvent); }
咱们能够在这里,再定义事件监听类,这些类具体实现了监听功能和事件处理功能。也能够用下面主程序中的匿名内部类来实现。原理同样。ide
3.定义事件源对象(具体的事件源,好比说,你点击一个button,那么button就是event source,要想使button对某些事件进行响应,你就须要注册特定的listener。这里指开关)函数
/** * 电源开关 * 事件源对象,相似于Swing中的button * Created by HuangYQ on 2016/5/31. */ public class Switch { private Vector switchListenerList = new Vector(); public void addListener(Object listener) { switchListenerList.add(listener); } protected void open() { SwitchEvent switchEvent = new SwitchEvent(this, "开"); notifyListeners(switchEvent); } protected void close() { SwitchEvent switchEvent = new SwitchEvent(this, "关"); notifyListeners(switchEvent); } private void notifyListeners(SwitchEvent switchEvent) { Iterator iterator = switchListenerList.iterator(); while (iterator.hasNext()) { SwitchListener switchListener = (SwitchListener) iterator.next(); switchListener.handleEvent(switchEvent); } } }
4.主程序学习
public class SwitchMain { public static void main(String[] args) { Switch switchTest = new Switch(); switchTest.addListener(new SwitchListener() { @Override public void handleEvent(SwitchEvent switchEvent) { //Do what ever you want ! System.out.println(switchEvent.getSwitchState()); } }); //触发 switchTest.open(); switchTest.close(); } }
运行:ui
开 关
仔细分析下程序,和咱们以前YY的监听器其实大体同样,
我的以为最难理解的就是事件对象SwitchEvent了。
问题
1.为何要继承EventObject?不继承行不行
2.事件和事件源有什么联系,为何还须要事件对象
答:
1.继承自EventObject只是为了规范,不实现固然能够。在handleEvent的时候,咱们能够经过事件对象拿到咱们须要的东西,这里面就有最基本的source,也就是这里的switch对象了,
2.事件和事件源关系并不大,事件对象里面包含source罢了,经过构造函数注入。this
[参考]