Java、LotusScript和JavaScript中的自定义事件编程(三)

2014-11-24 02:01:34 · 作者: · 浏览: 8
ner1); publisher.addEventListener("MyEvent2", new MyEvent2Listener1()); publisher.addEventListener("MyEvent2", new MyEvent2Listener2()); publisher.run(); // A MyEventPublisher publisher1 is running. // Publisher1 fires MyEvent1. // MyEvent1 handled in MyEvent1Listener1. // Publisher1 fires MyEvent2. // MyEvent2 handled in MyEvent2Listener1. // MyEvent2 handled in MyEvent2Listener2. Event information: // name: MyEvent2 // y: 30 // x: 10 } }

程序运行的结果附在MyEventTester的最后。依据面向对象设计与事件里对Java和C#事件编程的比较,同样可以C#写出类似的自定义事件框架,因为事件处理程序能以方法为单位添加和删除,并且多个处理程序能包容于一个收听者,所以代码会简短一些。

LotusScript

面向对象的LotusScript(六)之为自定义对象模拟事件一文给出了LotusScript中编写自定义事件的代码,在次重复一次:

Public EventResult As Boolean
Public Class EventPublisher
'定义通用的事件列表
Private EventList List As Variant
'添加事件处理程序
Public Function AddEventHandler(eventName As String, handler As String)
    Dim handlerList List As String
    Dim v As Variant
    If Iselement(EventList(eventName)) Then
        v=EventList(eventName)
        v(handler)=handler
        EventList(eventName)=v
    Else
        handlerList(handler)=handler
        EventList(eventName)=handlerList
    End If
End Function
'去除事件处理程序
Public Function RemoveEventHandler(eventName As String, handler As String)
    '需要在(Options)中添加%INCLUDE "lserr.lss"
    On Error ErrListItemDoesNotExist Goto ExitFunction
    Dim handlerList As Variant
    handlerList=EventList(eventName)
    Erase handlerList(handler)
    EventList(eventName)=handlerList
ExitFunction:
    Exit Function
End Function


'运行EventList中某事件的所有处理程序
Private Sub OnEvent(eventName As String)
    If Iselement(EventList(eventName)) Then
        Dim v As Variant
        v=EventList(eventName)
        Forall handler In v
            Execute handler
        End Forall
    End If
    
End Sub

End Class

同时该文也说明了这个框架的局限性:事件处理程序仅仅通过一个字符串来传递,无法检查类型和签名,缺乏安全性。只有通过公共变量才能在事件源和消费者之间传递事件的相关信息。事件处理程序必须定义在一个Script Library中,事件源才能通过Use语句引用并访问。这些限制的根源就是LotusScript里没有原生的传递函数的机制,这一点和Java相似,所以不得已利用了即时执行程序的Execute语句。其实我们也可以参照Java的事件编程所用的方法,把处理程序包含在收听者以内,将其以对象而非函数的形式登记到事件的发布者。如此,原来的局限性都迎刃而解,有兴趣的朋友可以试试。

java script

本文给出的Java的自定义事件框架虽然允许发布者灵活声明事件,但它的可重用性却还是受到语言本身的限制。任何想利用此框架发布事件的类都须继承starrow.util.EventPublisher类,但Java只允许单重继承,也就是很多已经在现有的类层次中有父类的类型无法利用EventPublisher的代码。C#的情况也一样。这其实是此类单重继承的面向对象语言的共有问题――代码重用的可能性受到制约。解决的选项有几个,在静态类型语言里或者采用C++这样更复杂、有争议的多重继承机制,或者引入Mixin(http://en.wikipedia.org/wiki/Mixin)之类的新途径;如果语言本身是动态类型的,比如java script这样的原型风格的面向对象机制,答案就很简单。下面的代码展示了一种java script中的自定义事件框架,它具有和Java版本同级别的灵活性,又方便任何自定义对象“安装”以获得自定义事件的能力。

var eventify = function(obj){
    var _listeners = {};
    
    obj.addListener = function(type, listener){
        if (!_listeners.hasOwnProperty(type)) {
            _listeners[type] = [];
        }
        _listeners[type].push(listener);
        return this;
    }
    
    obj.fire = function(event){
        if (typeof event === "string") {
            event = {
                type: event
            };
        }
        if (!event.type) { 
            throw new Error("Event object missing 'type' property.");
        }
        event.target = this;
        
        if (_listeners.hasOwnProperty(event.type)) {
            var listeners = _listeners[event.type];
            for (var i = 0, len = listeners.length; i < len; i++) {
                listeners[i].call(this, event);
            }
        }
        return this;
    }
    
    obj.removeListener = function(type, listener){
        if (_listeners.hasOwnProperty(type)) {
            var listeners = _listeners[type];
            for (var i = 0, len = listeners.length; i < len; i++) {
                if (listeners[i] === listener) {
                    listeners.splice(i, 1);
                    break;
                }
            }
        }
        return this;
    }
    return obj;
};

将任何对象传递给eventify函数,返回的对象就具备了发布事件的能力。添加和删除处理程序的方法分别为addListener和removeListener,触发事件的方法为fire。从发布者传递给收听者的事件参数对象event有两个属性type和target,分别为事件的名称和发布者。下面就是应用上述事件框架的一个简单例子。person自定义对象从eventify方法返回后声明了一个hunger事件,处理程序在Firefox浏览器的控制台打印出I'm hungery.

    var person={
        name