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

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

stdext.lua

local _ipairs = ipairs
function ipairs(t)local mt = getmetatable(t) if mt and mt.__ipairs thenreturn mt.__ipairs(t)endreturn _ipairs(t)
endlocal _pairs = pairs
function pairs(t)local mt = getmetatable(t)if mt and mt.__pairs thenreturn mt.__pairs(t)endreturn _pairs(t)
end

util.lua

require "stdext"local debug = debug
local string = string
local print = printlocal util = {}function util.trace(prefix)prefix = prefix .. " "return function(...)print(prefix .. string.format(...))end
endfunction util.callee()return debug.getinfo(2, "f").func
endfunction util.getupvalues(func)local u = {}local i = 0while true doi = i + 1local key, value = debug.getupvalue(func, i)if key thenu[key] = valueelsebreakendendreturn u
endreturn util

EventDispatcher.lua

local util = require "util"
local class = require "class"local trace = util.trace("[EventDispatcher]")
local assert = assert
local next = next
local 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 thenlist = hashlist.new()self._listeners[event] = listendlist:insert(owner or ANONYMOUS, listener, priority)
endfunction EventDispatcher:removeEventListener(event, listener, owner)assert(event)assert(listener)local list = self._listeners[event]if list thenlist:remove(owner or ANONYMOUS, listener)if list:empty() thenself._listeners[event] = nilendend
endfunction EventDispatcher:dispatchEvent(event, ...)assert(event, "event type is nil")if self:hasEventListener(event) thenfor _, owner, listener in pairs(self._listeners[event]) doif owner == ANONYMOUS thenlistener(self, ...)elselistener(owner, self, ...)endendend
endfunction EventDispatcher:hasEventListener(event)return self._listeners[event] ~= nil
end-------------------------------------------------------------------------------
-- hashlist
--
-------------------------------------------------------------------------------
local tostring = tostring
hashlist.__index = hashlistlocal function makeindex(owner, handler)return tostring(owner) .. "|" .. tostring(handler)
endfunction hashlist.new()local self = setmetatable({}, hashlist)self.header = {}self.header.next = self.headerself.header.prev = self.headerself.entries = {}return self
endlocal function itor(header, current)local entry = current.nextif entry ~= header thenreturn entry, entry.key, entry.valueend
endfunction hashlist:__pairs()return itor, self.header, self.header
endfunction hashlist:insert(key, value, priority)local idx = makeindex(key, value)if self.entries[idx] then return endlocal entry = {key = key, value = value, priority = priority}local header, current = self.headerif not priority thencurrent = header.prevelsecurrent = headerlocal next = current.nextwhile next ~= header doif not next.priority or priority <= next.priority thenbreakelsecurrent = nextnext = current.nextendendendentry.next = current.nextentry.prev = currentcurrent.next.prev = entrycurrent.next = entryself.entries[idx] = entry
endfunction hashlist:empty()return next(self.entries) == nil
endfunction hashlist:remove(key, value)local idx = makeindex(key, value)local entry = self.entries[idx]if entry thenentry.prev.next = entry.nextentry.next.prev = entry.prevself.entries[idx] = nilend
endreturn 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")

转载于:https://www.cnblogs.com/zhongfq/p/4178043.html

使用lua实现一个简单的事件派发器相关推荐

  1. 用Qt写一个简单的音乐播放器(三):增加界面(播放跳转与音量控制)

    一.前言 在用Qt写一个简单的音乐播放器(一):使用QMediaPlayer播放音乐中,我们已经知道如何去使用QMediaPlayer播放音乐. 在用Qt写一个简单的音乐播放器(二):增加界面(开始和 ...

  2. cocos 的EventHandler 事件派发器

    cocos 的EventHandler 事件派发器 cc.Component.EventHandler 类 官方说明 "EventHandler" 类用来设置场景中的事件回调,该类 ...

  3. 如何使用aframe.js构建一个简单的VR播放器

    在当今这个信息化的时代,虚拟现实(VR)已经开始逐渐成为一种新的生活方式.作为一名前端开发工程师,在学习和探索VR技术方面,aframe.js是一个非常有趣和有用的工具.在本文中,我将介绍如何使用af ...

  4. 用Qt写一个简单的音乐播放器(四):歌曲浏览、上一曲、下一曲

    一.前言 在用Qt写一个简单的音乐播放器(一):使用QMediaPlayer播放音乐中,我们已经知道如何去使用QMediaPlayer播放音乐. 在用Qt写一个简单的音乐播放器(二):增加界面(开始和 ...

  5. 使用Python制作一个简单的刷博器

    呵呵,不得不佩服Python的强大,寥寥几句代码就能做一个简单的刷博器. import webbrowser as web import time import oscount=0 while cou ...

  6. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  7. json string 格式_自己动手实现一个简单的JSON解析器

    作者:田小波 原文:http://cnblogs.com/nullllun/p/8358146.html 1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数 ...

  8. GStreamer 编写一个简单的MP3播放器

    本文介绍如何使用GStreamer 编写一个简单的MP3播放器. 1,需要使用mad解码插件,因此需要先安装gstreamer0.10-plugins-ugly 2,编写mp3播放器 下面来看看如何利 ...

  9. python实现雪花动态图_如何通过雪花算法用Python实现一个简单的发号器

    实现一个简单的发号器 根据snowflake算法的原理实现一个简单的发号器,产生不重复.自增的id. 1.snowflake算法的简单描述 这里的snowflake算法是用二进制的,有64位.其中41 ...

最新文章

  1. 川大 NLP 博士生被华为以 200 万年薪录用!分享以下科研及论文写作经验...
  2. AHOI2013 Round2 Day2 简要题解
  3. mfc cstring 写入文件_兄弟Brother单色激光传真一体机MFC系列不能写入此文件夹提示解决方案...
  4. fcntl函数参数F_GETPIPE_SZ、F_SETPIPE_SZ报错引出的关于linux-specific头文件的使用方法...
  5. ASP+MSSQL注入工具 web版 beta 3 final release
  6. 【原创】ucos信号量的操作及原理
  7. Linux系统编程----15(线程与进程函数之间的对比,线程属性及其函数,线程属性控制流程,线程使用注意事项,线程库)
  8. Linux编程make命令
  9. 【转】1.2SharePoint服务器端对象模型 之 对象模型概述(Part 2)
  10. mysql for 语句执行顺序_MySQL使用profile分析SQL语句执行过程
  11. 解决IDEA GIT密码输入错误后,报Authentication failed ... 不再弹出输入框,提交更新失败
  12. DevOps on DevCloud|如何构建Kotlin开发的Android Apps
  13. 习题3.12 另类循环队列 (20 分)
  14. 遍历map时删除不需要的元素方法
  15. Linux用户与组命令之groupadd
  16. Linux下maven安装
  17. opensaml2.0 java例子_OpenSAML 使用引导 I : 简介——关于OpenSAML你所需知道的一切
  18. Linux下登陆mysql服务器不需要输入账号密码信息
  19. 安装2000服务器显示文件挂起,MS sql server 2000安装中的提示挂起的解决方案。
  20. 怎样配置更完美的图形工作站

热门文章

  1. 小学生python入门-小学生都开始学的Python编程到底是什么?
  2. 3_HEIF/heic格式图片文件解析(20190107)
  3. java swing开源组件_Squareness
  4. Binary Tree Nodes(单表多实例查询)
  5. 原理分析之一:从JDBC到Mybatis
  6. 几种P2P流媒体开源项目介绍
  7. Django框架学习索引
  8. 为何 short s1 = 1; 是对的,而 float f=3.4; 是错的?
  9. 我的Android笔记--我对安卓系统的一些了解
  10. 会话管理-2.1.Session介绍