面向对象的LotusScript(六)之为自定义对象模拟事件和面向对象设计与事件两篇文章都提到事件是编程时对很多场景的抽象和解决模式,核心就是在两个对象之间建立一种“提醒”机制,当某件事发生时,作为发布者的对象提醒称为收听者或预订者的对象,后者执行特定的操作。在汽车火车上,一名乘客甲请 乘务员或者另一乘客乙到某站丙时提醒自己下车,就可以作为以上事件概念在生活中很好的原型。这里汽车到达丙站就是事件,乘客甲是收听者,乙是发布者,甲的请 是预订或登记事件处理程序;到达丙站,事件触发;乙提醒甲,甲执行处理程序――下车(唯一的细微差别是这里的事件发布者乙并没有导致事件发生即到达丙站)。
很多编程语言都预定义了大量的事件和发布者,例如图形界面上的各种控件及其事件。在运用这些事件以外,开发中有些场合为建模的对象自定义事件有助于设计出角色清晰的对象和它们之间有效的沟通。事件的机制既已清楚,自定义事件只需对象和函数这样基本的元件。有些语言显示地提供了自定义事件的语法,其他很多则需程序员根据事件的机制设计或者模拟。本文列举了Java、java script和LotusScript三种语言中自定义事件的代码以说明。
Java
参照java.util.EventObject、javax.swing.event.EventListenerList的JavaDoc,不难编写出Java中的自定义事件示例。
package starrow.demo;
import java.util.EventObject;
//Declare the event object passed as argument to the listener's handler method.
public class MyEvent extends EventObject {
public MyEvent(Object source) {
super(source);
}
}
package starrow.demo;
import java.util.EventListener;
//Declare the custom listener interface.
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent evt);
}
package starrow.demo;
//This class publishes the custom event MyEvent.
public class MyEventPublisher {
protected javax.swing.event.EventListenerList listenerList =
new javax.swing.event.EventListenerList();
public void addMyEventListener(MyEventListener listener) {
listenerList.add(MyEventListener.class, listener);
}
public void removeMyEventListener(MyEventListener listener) {
listenerList.remove(MyEventListener.class, listener);
}
private void fireMyEvent(MyEvent evt) {
MyEventListener[] listeners=listenerList.getListeners(MyEventListener.class);
for (MyEventListener listener : listeners){
try{
listener.myEventOccurred(evt);
}catch (Exception e){
e.printStackTrace();
}
}
}
public void run(){
//Fires MyEvent
fireMyEvent(new MyEvent(this));
}
}
package starrow.demo;
public class MyEventTester {
public static void main(String[] args){
MyEventPublisher publisher = new MyEventPublisher();
// Register for MyEvent from publisher
publisher.addMyEventListener(new MyEventListener() {
public void myEventOccurred(MyEvent evt) {
System.out.println("MyEvent was fired.");
}
});
publisher.run();
}
}
运行结果就是打印出MyEventwas fired.上面的代码是针对一个特定的事件MyEvent,如果发布者要声明另一个事件MyEvent2,就须重复写一套类似的代码。我们可以把事件的名称作为参数传递,写出更一般化的自定义事件代码。
package starrow.util;
import java.util.HashMap;
/**
* This class contains information relevant to the event,
* and is passed to the handler of the listener.
*
*/
public class EventArg {
//The event publisher.
Object source;
//A map used to hold event relevent information.
HashMap
info;
public EventArg(Object source, HashMap
info){ this.source=source; this.info=info; } public EventArg(Object source){ this.source=source; this.info=new HashMap
(); } public Object getSource() { return source; } public HashMap
getInfo() { return info; } //Export the get method of the inner map. public Object get(String key){ return info.get(key); } //Export the put method of the inner map. public EventArg put(String key, Object value){ info.put(key, value); return this; } } package starrow.util; /** * Any custom listener must implements this interface. */ public interface IEventListener { void handleEvent(Eve