码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-12-22 14:09:37      阅读:268      评论:0      收藏:0      [点我收藏+]

标签:

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

为了使用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")

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

标签:

原文地址:http://www.cnblogs.com/zhongfq/p/4178043.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!