首页 > 代码库 > 使用lua实现一个简单的事件派发器

使用lua实现一个简单的事件派发器

设计一个简单的事件派发器,个人觉得最重要的一点就是如何保证事件派发过程中,添加或删除同类事件,不影响事件迭代顺序和结果,只要解决这一点,其它都好办。

为了使用pairs遍历函数,重写了pairs(lua 5.2以上版本不需要):

stdext.lua

local _ipairs = ipairsfunction ipairs(t)    local mt = getmetatable(t)     if mt and mt.__ipairs then        return mt.__ipairs(t)    end        return _ipairs(t)endlocal _pairs = pairsfunction pairs(t)    local mt = getmetatable(t)    if mt and mt.__pairs then        return mt.__pairs(t)    end        return _pairs(t)end

util.lua

require "stdext"local debug = debuglocal string = stringlocal print = printlocal util = {}function util.trace(prefix)    prefix = prefix .. " "    return function(...)        print(prefix .. string.format(...))    endendfunction util.callee()    return debug.getinfo(2, "f").funcendfunction util.getupvalues(func)    local u = {}    local i = 0    while true do        i = i + 1        local key, value = http://www.mamicode.com/debug.getupvalue(func, i)        if key then            u[key] = value        else            break        end    end    return uendreturn util

EventDispatcher.lua

local util = require "util"local class = require "class"local trace = util.trace("[EventDispatcher]")local assert = assertlocal next = nextlocal pairs = pairslocal ANONYMOUS = {}local hashlist = {}local EventDispatcher = class("EventDispatcher")function EventDispatcher:ctor()    self._listeners = {}endfunction EventDispatcher:addEventListener(event, listener, owner, priority)    assert(event)    assert(listener)        local list = self._listeners[event]    if not list then        list = hashlist.new()        self._listeners[event] = list    end        list:insert(owner or ANONYMOUS, listener, priority)endfunction EventDispatcher:removeEventListener(event, listener, owner)    assert(event)    assert(listener)        local list = self._listeners[event]    if list then        list:remove(owner or ANONYMOUS, listener)        if list:empty() then            self._listeners[event] = nil        end    endendfunction EventDispatcher:dispatchEvent(event, ...)    assert(event, "event type is nil")        if self:hasEventListener(event) then        for _, owner, listener in pairs(self._listeners[event]) do            if owner == ANONYMOUS then                listener(self, ...)            else                listener(owner, self, ...)            end        end    endendfunction EventDispatcher:hasEventListener(event)    return self._listeners[event] ~= nilend--------------------------------------------------------------------------------- hashlist---------------------------------------------------------------------------------local tostring = tostringhashlist.__index = hashlistlocal function makeindex(owner, handler)    return tostring(owner) .. "|" .. tostring(handler)endfunction hashlist.new()    local self = setmetatable({}, hashlist)    self.header = {}    self.header.next = self.header    self.header.prev = self.header    self.entries = {}    return selfendlocal function itor(header, current)    local entry = current.next    if entry ~= header then        return entry, entry.key, entry.value    endendfunction hashlist:__pairs()    return itor, self.header, self.headerendfunction hashlist:insert(key, value, priority)    local idx = makeindex(key, value)    if self.entries[idx] then return end    local entry = {key = key, value = http://www.mamicode.com/value, priority = priority}    local header, current = self.header    if not priority then        current = header.prev    else        current = header        local next = current.next        while next ~= header do            if not next.priority or priority <= next.priority then                break            else                current = next                next = current.next            end        end    end        entry.next = current.next    entry.prev = current    current.next.prev = entry    current.next = entry        self.entries[idx] = entryendfunction hashlist:empty()    return next(self.entries) == nilendfunction hashlist:remove(key, value)    local idx = makeindex(key, value)    local entry = self.entries[idx]    if entry then        entry.prev.next = entry.next        entry.next.prev = entry.prev        self.entries[idx] = nil    endendreturn EventDispatcher

 

示例:

local class = require "class"local EventDispatcher = require "EventDispatcher"local A = class("A", EventDispatcher)function A:ctor()    self:addEventListener("test", self.testHandler, self)endfunction A:testHandler()    print("test in testHandler")endlocal a = A.new()a:addEventListener("test", function()    a:removeEventListener("test", util.callee())    print("test outside")end)a:addEventListener("test", function()    print("test priority")end, nil, 0)

a:dispatchEvent("test", "a", "b")
a:dispatchEvent("test", "a", "b")

使用lua实现一个简单的事件派发器