本文是仿照 .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); }
独立工作事件
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()); } } }
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中的很多机制是编程实现而不是类库和语言特性支持的缘故,下图是两种实现的比较。
java | c# | 说明 | |
效率 | 采用多态,相对高 | 采用委托,相对低。 | 应该说,它们都是在运行时获取对哪个对象的哪个方法进行调用,但是采用多态相对于委托效率高一点。 |
是否支持静态方法调用 | 否 | 是 | java采用多态,当然不能把方法声明为static;c#中delegate中的_object可以为null来实现对静态方法的调用 |
是否类型安全 | 是 | 是 | 它们都会在编译时对响应函数进行参数检查,类型安全。 |
开发者易用性 | 两级实体对象:事件源-与事件响应者 | 三级实体对象:事件源-委托-事件响应者 | 由于有delegate的封装,不用编写事件注册/注销之类的代码,c#事件处理易用性相对高;注意,虽然java中采用接口来规范响应函数,但这里却说java中是两级实体对象,是因为在运行时并不存在接口的实例(实际上,接口也不可实例化,呵呵) |