事件监听器

1.背景

类是对象的抽象,是一个特征集,我们会定义一些成员变量和构造函数来体现不同实例之间的差异。比如孩子中会有名字等

当然在类中也会有一些成员方法,如孩子们可以玩游戏等。

这些都是我们可以根据需求与实际预知并抽象出来的,但是如果有这样一种行为,对象自己无法控制什么时候会发生,如孩子们被告知回家吃饭,然后每个孩子心里所想,做什么我们都无法预知。而这些无法用简单的成员变量去描述。

一千个孩子有一千个孩子的想法,所以除非我们事先知道每个孩子的想法,然后预先创建一千个想法的孩子类,可是刚好只有一个孩子被叫着吃饭了,其余的就浪费了。

所以必须有有这样一种机制来处理这种情况:同一类事物遇到相同一个事件,所表现的行为不同。

在孩子类中显然不能处理这件事情,因为孩子的数量我们无法确定,如果增加一个孩子就要去修改孩子类,显然是不合理的。

所以需要把孩子“被叫回家吃饭”这个事件拉出来单独处理,交给别人去做,于是就有了监听器。


2.原理与实例

监听器,负责监听事件的发生,在Java中,就是一个接口,里面包含事件方法

interface EventListener {
	public void event();
}

对于需要监听的对象,也就是“事件源”,我们需要添加一个监听器,当事件源事件被出发时,我们将它交给监听器

class EventSource{
	EventListener listener;
	public void event(){
		listener.event();
	}
}
到现在,我们已经将事件交给了监听器去处理,但是监听器需要去实例化才能做事情,也就是注册监听器

class EventSource{
	EventListener listener;
	public void event(){
		listener.event();
	}
	public void addEventListener(EventListener listener){
		this.listener = listener;
	}
}
这样,我们只需要为每个事件源注册一个监听器,让注册的监听器去处理事件发生后需要做的事情

class Test{
	public static void main(String[] args){
		EventSource es = new EventSource();
		es.addEventListener(new EventListener() {
			
			@Override
			public void event() {
				// TODO Auto-generated method stub
				
			}
		});
	}
}
我们来看一下流程,首先我们需要创建EventSource,并添加一个listener,当EventSource的event被触发,会执行listener.event();联系前面讲到的多态,便实现了事件监听的过程。

联系下回调与事件监听,回调是一种思想,它可以实现代码的执行时间不在依赖于自身的模块,而是由其他模块控制,无论面向对象还是面向过程。

而事件监听是利用回调机制结合接口的特点实现的一种模式,也就是观察者模式。

我们实现一下孩子被妈妈叫去吃饭的例子:

interface Listener {
	public void istoldBack();
}
class Children{
	
	String name;
	Listener backhomeListener;
	
	public Children(String name){
		this.name = name;
	}
	
	public void playing(){
		System.out.println(name + "is playing()");
	}
	
	public void backHome(){
		backhomeListener.istoldBack();
	}
	public void addBackhomeListener(Listener backhomeListener){
		this.backhomeListener = backhomeListener;
	}
	public String getName(){
		return this.name;
	}
}
class Mom{
	public void backHome(Children child){
		System.out.println("妈妈:"+child.getName()+"回家吃饭了");
		child.backHome();
	}
}
public class ListenerTest{
	public static void main(String[] args){
		Mom mom = new Mom();
		Children xiaoming = new Children("xiaoming");
		Children xiaohong = new Children("xiaohong");
		xiaoming.playing();
		xiaohong.playing();
		xiaoming.addBackhomeListener(new Listener() {
			
			@Override
			public void istoldBack() {
				// TODO Auto-generated method stub
				System.out.println("xiaoming:我要回家吃饭");
			}
		});
		xiaohong.addBackhomeListener(new Listener() {
			
			@Override
			public void istoldBack() {
				// TODO Auto-generated method stub
				System.out
						.println("xiaohong:我不回去吃了");
			}
		});
		mom.backHome(xiaoming);
		mom.backHome(xiaohong);
	}

}

运行结果:

xiaomingis playing()
xiaohongis playing()
妈妈:xiaoming回家吃饭了
xiaoming:我要回家吃饭
妈妈:xiaohong回家吃饭了
xiaohong:我不回去吃了

3.疑问

匿名类,看以下代码:

xiaoming.addBackhomeListener(new Listener() {
			
			@Override
			public void istoldBack() {
				// TODO Auto-generated method stub
				System.out.println("xiaoming:我要回家吃饭");
			}
		});
Listener明明是是个接口,如何实例化的?

匿名类有两种实现方式,一种是继承一个类,重写其方法,另一种是实现一个接口

此处是实现了一个接口,newListener()实质上是实例化了一个继承Listener这个接口的子类,而并非实例化了接口。

使用匿名类只是为了一些特殊的实现,比如此处就是为了实现Listener中的istoldBack()方法,当让你也可以创建一个新类继承这个接口,然后再去实现,但是使用匿名类是代码更简洁,模块也清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值