标签:
设计一个简单的事件派发器,个人觉得最重要的一点就是如何保证事件派发过程中,添加或删除同类事件,不影响事件迭代顺序和结果,只要解决这一点,其它都好办。
为了使用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(2, "f").func end function util.getupvalues(func) local u = {} local i = 0 while true do i = i + 1 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, 0)
a:dispatchEvent("test", "a", "b")
a:dispatchEvent("test", "a", "b")
标签:
原文地址:http://www.cnblogs.com/zhongfq/p/4178043.html