您的位置:首页 > 编程语言 > Java开发

Java监听:一个Java睡前故事(Java Listener: A Java Bedtime Story)

2009-08-25 10:26 651 查看

Java监听:一个Java睡前故事(Java Listener: A Java Bedtime Story)

作者: 杨帆


本文是仿照 .NET Delegates: A C# Bedtime Story

的功能实现的Java版源代码,时间原因,没有给出文字故事

。请参见原文链接。

接口定义

package cn.steven.demo;

import java.util.EventListener;
import java.util.EventObject;
/**
* 监听接口 用于处理各种事件
* 此处设计与JDK不同
*/
public interface StevenEventListener extends EventListener {
public void doListen(EventObject e);
}


package cn.steven.demo;
/**
* 评价接口
*/
public interface IAppraisable {
//评价的方法
public void appraise(String name, int degree);
}


[/code]

事件

独立工作事件

package cn.steven.demo;
import java.util.EventObject;
public class WorkEvent extends EventObject {

private String eventMsg = "干活了";

public String getEventMsg() {
return eventMsg;
}
public void setEventMsg(String eventMsg) {
this.eventMsg = eventMsg;
}

/**
* 自动升成的serialVersionUID用于序列化
*/
private static final long serialVersionUID = 6232430258434094316L;
/**
* @param source 事件源
*/
public WorkEvent(Object source) {
super(source);
}
}


生活事件 (注意此事件有两个子类)

package cn.steven.demo;
import java.util.EventObject;
public abstract class LifeEvent extends EventObject {
public abstract String getEventMsg();

public LifeEvent(Object source) {
super(source);
}
private static final long serialVersionUID = -5117554641874171524L;
}


package cn.steven.demo;
public class BornEvent extends LifeEvent {
private String eventMsg = "出生";

public String getEventMsg() {
return eventMsg;
}
public void setEventMsg(String eventMsg) {
this.eventMsg = eventMsg;
}
public BornEvent(Object source) {
super(source);
}
private static final long serialVersionUID = 8880371520168303175L;
}


package cn.steven.demo;
public class DieEvent extends LifeEvent {
public DieEvent(Object source) {
super(source);
}
private String eventMsg = "死亡";
public String getEventMsg() {
return eventMsg;
}
public void setEventMsg(String eventMsg) {
this.eventMsg = eventMsg;
}
private static final long serialVersionUID = 5643693360168396103L;
}


监听器

package cn.steven.demo;

import java.util.EventObject;

public class Boss implements StevenEventListener{

/**
* 只对WorkEvent事件响应
*/
@Override
public void doListen(EventObject e) {
if(e instanceof WorkEvent){
System.out.println("老板:"+e.getSource()+"开工啦!");

try {
//老板由于事务繁忙,打分时间要长,所以需要异步调用节省时间
Thread.currentThread().sleep(500);
} catch (InterruptedException e1) {
}

Object source = e.getSource();
//如果可以打分
if(source instanceof IAppraisable){
IAppraisable ia = (IAppraisable)source;
//老板打分
ia.appraise("老板", 5);
}
}
}

}


package cn.steven.demo;

import java.util.EventObject;

public class God implements StevenEventListener {

@Override
public void doListen(EventObject e) {
if (e instanceof LifeEvent) {
LifeEvent de = (LifeEvent) e;
System.out.println("上帝:(生命时间)" + de.getSource() + de.getEventMsg());
}

if (e instanceof WorkEvent) {
WorkEvent de = (WorkEvent) e;

System.out.println("上帝:(工作时间)" + de.getSource() + de.getEventMsg());

try {
//god由于事务繁忙,打分时间要长,所以需要异步调用节省时间
Thread.currentThread().sleep(1000);
} catch (InterruptedException e1) {
}

Object source = e.getSource();
//如果可以打分
if(source instanceof IAppraisable){
IAppraisable ia = (IAppraisable)source;
//上帝打分
ia.appraise("上帝", 6);
}
}
}
}


package cn.steven.demo;

import java.util.EventObject;

public class Satan implements StevenEventListener {

@Override
public void doListen(EventObject e) {
if (e instanceof DieEvent) {
DieEvent de = (DieEvent) e;
System.out.println("撒旦:" + de.getSource() + de.getEventMsg());
}
}

}


[/code]

事件源

package cn.steven.demo;
import java.util.EventObject;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
//Worker的工作是可以评价的IAppraisable
public class Worker implements IAppraisable {
private String name;
private Map<Class<? extends EventObject>, List<StevenEventListener>> listenerMap;
public Worker(String name) {
this.name = name;
listenerMap = new HashMap<Class<? extends EventObject>, List<StevenEventListener>>();
}
@Override
public String toString() {
return name;
}
// 增加监听器
public synchronized void addListener(StevenEventListener listener,
Class<? extends EventObject>... eventClass) {
if (null != listenerMap) {
if (eventClass.length <= 0) {
throw new RuntimeException("至少指定一个事件进行监听!");
} else {
for (int i = 0; i < eventClass.length; i++) {
Class<? extends EventObject> e = eventClass[i];
List<StevenEventListener> list = null;
if (listenerMap.containsKey(e)) {
list = listenerMap.get(e);
}
if (null == list) {
list = new LinkedList<StevenEventListener>();
}
if (list.contains(listener)) {
// 如果已存在,不操作,处理下一个事件
continue;
}
list.add(listener);
listenerMap.put(e, list);
}
}
}
}
// 移除事件监听器
public synchronized void removeEventListener(StevenEventListener listener,
Class<? extends EventObject>... eventClass) {
if (null != listenerMap) {
// 如果没给定第二个参数
if (eventClass.length <= 0) {
// 在所有事件中移除监听器
for (Map.Entry<Class<? extends EventObject>, List<StevenEventListener>> entry : listenerMap
.entrySet()) {
List<StevenEventListener> list = entry.getValue();
if (null != list) {
list.remove(listener);
}
}
} else {
// 在给定的事件中移除监听器
for (int i = 0; i < eventClass.length; i++) {
Class<? extends EventObject> e = eventClass[i];
if (listenerMap.containsKey(e)) {
List<StevenEventListener> list = listenerMap.get(e);
if (null != list) {
list.remove(listener);
}
}
}
}
}
}
public synchronized void removeListener(StevenEventListener listener) {
if (null != listenerMap) {
}
}
// 移除所有监听器
public synchronized void removeAllListener() {
if (null != listenerMap) {
listenerMap.clear();
}
}
// 处理监听
public void doEvent(final EventObject e) {
if (null != listenerMap) {
// 在此,如果key是event的祖先也可以监听
for (Map.Entry<Class<? extends EventObject>, List<StevenEventListener>> entry : listenerMap
.entrySet()) {
if (entry.getKey().isInstance(e)) {
if (null != entry.getValue()) {
for (final StevenEventListener stevenEventListener : entry
.getValue()) {
if (null != stevenEventListener) {
// 处理监听 同步方法
// stevenEventListener.doListen(e);
// 处理监听 异步多线程方法
Thread t = new Thread(new Runnable() {
public void run() {
stevenEventListener.doListen(e);
}
});
// 如果设置为守护进程,程序退出后此进程关闭
// t.setDaemon(true);
// 如果不设置为守护,则程序退出后线程还会运行
t.start();
// 如果想再次等待非守护想成结束在结束进程(阻塞调用线程,直到某个线程终止时为止。变为同步),则join
// try {
// t.join();//必须放在线程启动的后面
// } catch (InterruptedException e1) {
// }
}
}
}
}
}
}
}
// 工作方法
public void work() {
System.out.println("@我干活了!");
doEvent(new WorkEvent(this));
}
public void born() {
System.out.println("@我出生了!");
doEvent(new BornEvent(this));
}
public void die() {
System.out.println("@我死了!");
doEvent(new DieEvent(this));
}
//对工作打分 需要回调(callback)
@Override
public void appraise(String name, int degree){
System.out.println(name+"评价工作为"+degree+"分!");
}

}


运行

package cn.steven.demo;
public class Run {
public static void main(String[] args) {
System.out.println("/t进程开始");
// 事件源
Worker worker = new Worker("东方不败");
Boss boss = new Boss();
God god = new God();
Satan satan = new Satan();
// 老板只对工作关心
worker.addListener(boss, WorkEvent.class);
// god对两种时间都关心
worker.addListener(god, WorkEvent.class, LifeEvent.class);
// satan对死亡关心
worker.addListener(satan, DieEvent.class);
worker.work();
worker.born();
worker.die();
System.out.println("/t进程结束 在此后出现的为非守护线程");
}
}


运行结果

进程开始
@我干活了!
@我出生了!
老板:东方不败开工啦!
@我死了!
上帝:(工作时间)东方不败干活了
上帝:(生命时间)东方不败出生
进程结束 在此后出现的为非守护线程
撒旦:东方不败死亡
上帝:(生命时间)东方不败死亡
老板评价工作为5分!
上帝评价工作为6分!


后记

java版的故事很明显要比c#的代码多,这实际上是由于Java中的很多机制是编程实现而不是类库和语言特性支持的缘故,下图是两种实现的比较。

javac#说明
效率采用多态,相对高采用委托,相对低。应该说,它们都是在运行时获取对哪个对象的哪个方法进行调用,但是采用多态相对于委托效率高一点。
是否支持静态方法调用java采用多态,当然不能把方法声明为static;c#中delegate中的_object可以为null来实现对静态方法的调用
是否类型安全它们都会在编译时对响应函数进行参数检查,类型安全。
开发者易用性两级实体对象:事件源-与事件响应者三级实体对象:事件源-委托-事件响应者由于有delegate的封装,不用编写事件注册/注销之类的代码,c#事件处理易用性相对高;注意,虽然java中采用接口来规范响应函数,但这里却说java中是两级实体对象,是因为在运行时并不存在接口的实例(实际上,接口也不可实例化,呵呵)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: