1 //欢迎您的点评
  2
  3 import  java.lang.reflect.Method;
  4 import  java.util.ArrayList;
  5 import  java.util.Hashtable;
  6 import  java.util.Iterator;
  7
  8 import  org.apache.commons.logging.Log;
  9 import  org.apache.commons.logging.LogFactory;
 10
 11 /**
 12  * 事件基类
 13  *  @author  Richard Lee
 14  * 子类必须创建两个构造函数,一个为默认构造函数,一个为override受保护构造函数EventBase(Class handlerType)
 15   */

 16 public   abstract   class  EventBase  {
 17   ////////////////////////////////////////////
 18   // 类常量
 19  
 20   //  StringBuffer初始大小
 21   private   static   final   int  StringBufferInitSize  =   256 ;
 22  
 23   private   static   final  Log log  =  LogFactory.getLog(EventBase. class );
 24
 25   ////////////////////////////////////////////
 26   // 成员变量,在创建对象时赋值,以后不可以改变。
 27  
 28   // 同步根对象
 29   public   final  Object SyncRoot  =   new  Object();
 30  
 31   // 事件监听者列表
 32   private   final  ArrayList listeners  =   new  ArrayList();
 33  
 34   // 事件方法缓存
 35   private   final  Hashtable eventMethodCache  =   new  Hashtable();
 36  
 37   // 事件处理对象(接口)类型
 38   private   final  Class handlerType;
 39  
 40   ////////////////////////////////////////////
 41   // 私有方法
 42  
 43   /**
 44   * 检查事件处理对象的类型是否符合要求
 45   *  @param  handler
 46   *  @return
 47    */

 48   private   boolean  checkHandlerType(Object handler) {
 49    return   this .handlerType.isInstance(handler);
 50  }

 51  
 52   /**
 53   * 根据事件方法的名称查找事件函数
 54   * 约束:事件函数不能够重载(overload)
 55   *  @param  eventMethodName
 56   *  @return
 57    */

 58   private  Method getEventMethodByName(String eventMethodName) {
 59    if (eventMethodCache.containsKey(eventMethodName)) {
 60     return  (Method)eventMethodCache.get(eventMethodName);
 61   }

 62    throw   new  RuntimeException( " There is no ' "   +  eventMethodName  +   " ' event. " );
 63  }

 64  
 65   ////////////////////////////////////////////
 66   // 受保护方法
 67  
 68   /**
 69   * 受保护构造函数,创建处理接口方法缓存
 70   *  @param  handlerType
 71    */

 72   protected  EventBase(Class handlerType) {
 73    this .handlerType  =  handlerType;
 74   Method [] ms  =  handlerType.getMethods();
 75    for  ( int  i  =   0 ; i  <  ms.length; i ++ {
 76    eventMethodCache.put(ms[i].getName() , ms[i]);
 77   }

 78  }

 79  
 80   /**
 81   * 抛出事件
 82   *  @param  eventMethodName
 83   *  @param  args
 84    */

 85   protected   void  fireEvent(String eventMethodName , Object [] args) {
 86   Iterator it  =   this .listeners.iterator();
 87    while (it.hasNext()) {
 88    Object handler  =  it.next();
 89     if ( null   ==  handler)  {
 90      continue ;
 91    }

 92     try   {
 93     Method m  =  getEventMethodByName(eventMethodName);
 94     m.invoke(handler , args);
 95    }
  catch  (Throwable e)  // 捕捉所有的异常,统一通过onError方法处理。
 96     onError(eventMethodName , handler , e);
 97    }

 98   }

 99  }

100  
101   /**
102   * 事件执行过程出错的处理, 子类根据不同的异常类型进行处理
103   *  @param  eventName
104   *  @param  eventHandler
105   *  @param  e
106    */

107   protected   void  onError(String eventName , Object eventHandler, Throwable e) {
108    try {
109     if (log.isErrorEnabled()) {
110     StringBuffer msg  =   new  StringBuffer(StringBufferInitSize);
111     msg.append( " Event class: \ "" ).append(this.getClass().getName());
112     msg.append( " \ " , \ "" ).append(eventName).append( " \ "  event execute failed. Event handler: \ "" );
113      if ( null   !=  eventHandler) {
114      msg.append(eventHandler.toString());
115     }
else {
116      msg.append( " null reference " );
117     }

118     msg.append( ' " ' );
119     log.error(msg , e);
120    }

121   }
catch (Throwable ex) {
122    log.error( " onError execute failed. "  , ex);
123   }

124  }

125  
126   ////////////////////////////////////////////
127   // 公共护方法
128  
129   public   boolean  addHandler(Object handler) {
130    if (checkHandlerType(handler)) {
131     return  listeners.add(handler);
132   }

133    throw   new  IllegalArgumentException( " Handler type is invalid, addHandler method failed. " );
134  }

135  
136   public   boolean  removeHandler(Object handler) {
137    if (checkHandlerType(handler)) {
138     return  listeners.remove(handler);
139   }

140    throw   new  IllegalArgumentException( " Handler type is invalid, removeHandler method failed. " );
141  }

142  
143   public   void  removeAllHandler() {
144    this .listeners.clear();
145  }

146  
147   public   boolean  hasHandler() {
148    return   ! listeners.isEmpty();
149  }

150 }

151
152

使用范例:
首先定义一个事件处理器的接口
public interface ITestEventHandler {
    
void onEnter(Object sender, Object arg);
    
void onExit(Object sender, Object arg);
}

接着我们就编写一个类作为事件源(Observerable)
/**
 * 活动的事件
 * 
@author Richard Lee
 * 非线程安全,需要使用者自行手工同步
 
*/

public class TestEvents extends EventBase implements ITestEventHandler {
    
public TestEvents(){
        
this(ITestEventHandler.class);
    }


    
protected TestEvents(Class handlerType) {
        
super(handlerType);
    }


    
public void onEnter(Object sender, Object arg) {
        fireEvent(
"onEnter" , new Object[]{sender, arg});
    }


    
public void onExit(Object sender, Object arg) {
        fireEvent(
"onExit" , new Object[]{sender, arg});
    }

}

接着我们就编写一个类作为事件处理器:

public class TestEventHandler implements ITestEventHandler {

    
public void onEnter(Object sender, Object arg) {
        System.out.println(
"OnEnter, sender: " + sender + ", arg: " + arg);
    }



    
public void onExit(Object sender, Object arg) {
        System.out.println(
"onExit, sender: " + sender + ", arg: " + arg);
    }

}


OK,这样就可以了,当然我们还需要一些客户端的代码来将TestEventHandler的实例注册到TestEvents的实例中监听事件,然后我们就可以在TestEvents 类中需要的地方调用onEnter或者onExit,EventBase会自动的调用监听器的相应方法。


对Observer/Observable的优点:1.类型安全。2.可以有多个事件函数(在接口中任意定义)而不像Observer只有一个。

缺点:1.编写子类略现复杂。2.未做到线程安全。

欢迎评论和建议,谢谢。

Feedback

# re: 一个事件的基类,目标为改进j2sdk中的Observer  回复  更多评论   

2006-04-27 08:51 by 指教了
1,j2sdk中的Observer/Observable难道就不类型安全?
2,所谓“可以有多个事件函数”,没有很大意义,一个和多个没有本质区别;
3,你把Observable(TestEvents)也变成一个类型Observer(ITestEventHandler),你认为这样设计在类型层次上elegant?还有,如果真是这样的设计,eventBase(Class handlerType)是不是有点可笑?(“自己不知道自己”?)


“改进j2sdk中的……”这种标题还是少用为好,免得……

# re: 一个事件的基类,目标为改进j2sdk中的Observer  回复  更多评论   

2006-04-27 14:28 by iceboundrock
谢谢您的指教,对于这三个方面,我是这么考虑的:
1,j2sdk中的Observer/Observable难道就不类型安全?
没错啊,因为接口设计的太粗,所以无法保证回调时一定传入监听器需要的类型。
2,多个事件函数的意义在于可以清晰的表明事件的含义,并且提高效率。监听器不必自己处理所有的事件。
3,TestEvents实现ITestEventHandler的确不够优雅,不过这是为了程序编写上的方便。另外因为TestEvents可以实现很多接口,所以把事件处理类型传递进去,可以减少一部分工作。您觉得这块需要如何改进呢?
这个类的目标是改进Observer,我也的确认为对Observer做出了一些改善,所以我保留标题。

只有注册用户登录后才能发表评论。


网站导航:
 

posts - 10, comments - 15, trackbacks - 0, articles - 0

Copyright © iceboundrock