package com.xiaolu.eventdemo;
import java.util.EventListener;
import java.util.EventObject;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @class EventDemo
* @author xiaolu
* @date 2015年11月19日 上午10:40:51
* @purpose 实现java中自定义事件
*/
/*
* 最近重新翻看了c#的自定义事件,回头实现下java中的自定义事件。
*/
/*
* java中自定义事件,需要知道三个角色:
*
* 事件对象: 一般说来,事件对象需要从EventObject类进行继承,
* 事件对象承载了事件发生时向监听者【对事件感兴趣的类】发送 的封装参数,
*EventArgs继承的附加信息类】。
*
* 事件源: 事件源是事件由谁发出的。比如一个Button按钮,
* 在单击时会有"Click"事件产生,那么事件源就是Button按钮。
* 通俗的说就是产生事件的"源头"。
*
* 对事件进行监听【也就是哪些对事件感兴趣的客户(类),在期望的
* 事件发生时,需要有一些"动作"】
*/
/*
* 背景: 有新的邮件到来时,需要向传真机和寻呼机发送消息。
* 【和C#事件那个背景一样,体会下两者的实现思想】
*/
// 按照一般习惯,先定义事件源
//我们需要自己实现对事件的注册,撤销注册等【c#直接有+=,-=】
// 同时,类似于c#中的事件委托,我们需要定义一个事件监听者接口
//【统一具体事件监听者的“回调”方法签名形式】
// 定义事件对象【叫做事件状态对象更好点,它只是传达事件相关附加信息】
class NewMailObject extends EventObject {
private static final long serialVersionUID = 1L;
private String from;
private String to;
private String subject;
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public String getSubject() {
return subject;
}
public NewMailObject(Object source, String from, String to, String subject) {
super(source);
this.from = from;
this.to = to;
this.subject = subject;
}
}
interface NewMailListener extends EventListener {
public void NewMailComing(NewMailObject nmo);
public void register(MailManager mm);
public void unregister(MailManager mm);
}
class MailManager {
// 维护一个事件监听者集合【使用Set,不允许重复注册】
private Set<NewMailListener> listeners = new HashSet<NewMailListener>();
/**
* @function register
* @param num
* 事件监听者
* @purpose 具体事件监听者向事件源注册自己
*/
public void register(NewMailListener num) {
if (num != null) {
listeners.add(num);
}
}
/**
* @function unregister
* @param unm
* 事件监听者
* @purpose 具体事件监听者从事件源撤销自己【不再关注此事件】
*/
public void unregister(NewMailListener unm) {
if (unm != null) {
if (listeners.contains(unm)) {
listeners.remove(unm);
unm = null;
}
}
}
/**
* @function OnNewMailComming
* @param nmo
* @purpose 邮件到来时的响应
*/
protected void OnNewMailComming(NewMailObject nmo) {
// 一些自己的处理逻辑
notifyListeners(nmo);// 发出通知
}
/**
* @function notifyListeners
* @param nmo
* 邮件信息
* @purpose 当邮件到来时,通知集合中的事件监听者
*/
private void notifyListeners(NewMailObject nmo) {
Iterator<NewMailListener> iter = listeners.iterator();
while (iter.hasNext()) {
iter.next().NewMailComing(nmo);
}
}
// 为了实例完整运行,创建一个模拟邮件到来函数
public void simulateNewMailComming() {
OnNewMailComming(new NewMailObject(this, "xiaolu", ", "this is a demo!"));
}
}
// 创建具体监听者类
class Posage implements NewMailListener {
@Override
public void NewMailComing(NewMailObject nmo) {
System.out.println("Posage received : " + nmo.getSubject());
}
@Override
public void register(MailManager mm) {
mm.register(this);
}
@Override
public void unregister(MailManager mm) {
mm.unregister(this);
}
}
class Fax implements NewMailListener {
@Override
public void NewMailComing(NewMailObject nmo) {
System.out.println(
"Fax receved : from : " + nmo.getFrom() +
+ nmo.getSubject());
}
@Override
public void register(MailManager mm) {
mm.register(this);
}
@Override
public void unregister(MailManager mm) {
mm.unregister(this);
}
}
//驱动类
public class EventDemo {
public static void main(String[] args) {
MailManager mm = new MailManager();//创建事件源
NewMailListener listener1 = new Fax();
NewMailListener listener2 = new Posage();
listener1.register(mm);
listener2.register(mm);
mm.simulateNewMailComming();
}
}
/*
* ps: 在设计这个NewMailListener的时候,纠结了好一会,
* 网上大多数实现都是没有register/unregister这样的接口方法的
* 那么在Main【驱动类中】,就需要写下
* mm.register(listener1);
* mm.register(listener2);
* 这样的语句:不和符合语义: 注册应该是注册者自己的行为。而不应该
* 是事件源去注册。
* 有两段完全几乎重复的代码,可以考虑在接口下建立一个
* 适配器【此处就不再写了】
* 还是无法阻止外部去这样调用:
* mm.register(listener1);....
* 如果有好的想法和建议,欢迎讨论。
*/