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

时间:2023-03-08 23:28:19
使用lua实现一个简单的事件派发器

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

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

stdext.lua

local _ipairs = ipairs
function ipairs(t)
local mt = getmetatable(t)
if mt and mt.__ipairs then
return mt.__ipairs(t)
end return _ipairs(t)
end local _pairs = pairs
function 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 = debug
local string = string
local print = print local util = {} function util.trace(prefix)
prefix = prefix .. " "
return function(...)
print(prefix .. string.format(...))
end
end function util.callee()
return debug.getinfo(, "f").func
end function util.getupvalues(func)
local u = {}
local i =
while true do
i = i +
local key, value = debug.getupvalue(func, i)
if key then
u[key] = value
else
break
end
end return u
end return util

EventDispatcher.lua

local util = require "util"
local class = require "class" local trace = util.trace("[EventDispatcher]")
local assert = assert
local next = next
local pairs = pairs local ANONYMOUS = {}
local hashlist = {} local EventDispatcher = class("EventDispatcher") function EventDispatcher:ctor()
self._listeners = {}
end function 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)
end function 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
end
end function 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
end
end function EventDispatcher:hasEventListener(event)
return self._listeners[event] ~= nil
end -------------------------------------------------------------------------------
-- hashlist
--
-------------------------------------------------------------------------------
local tostring = tostring
hashlist.__index = hashlist local function makeindex(owner, handler)
return tostring(owner) .. "|" .. tostring(handler)
end function hashlist.new()
local self = setmetatable({}, hashlist)
self.header = {}
self.header.next = self.header
self.header.prev = self.header
self.entries = {}
return self
end local function itor(header, current)
local entry = current.next
if entry ~= header then
return entry, entry.key, entry.value
end
end function hashlist:__pairs()
return itor, self.header, self.header
end function hashlist:insert(key, value, priority)
local idx = makeindex(key, value) if self.entries[idx] then return end local entry = {key = key, value = 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] = entry
end function hashlist:empty()
return next(self.entries) == nil
end function 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
end
end return EventDispatcher

示例:

local class = require "class"
local EventDispatcher = require "EventDispatcher" local A = class("A", EventDispatcher) function A:ctor()
self:addEventListener("test", self.testHandler, self)
end function A:testHandler()
print("test in testHandler")
end local 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, ) a:dispatchEvent("test", "a", "b")
a:dispatchEvent("test", "a", "b")