基于lua的观察者模式应用:事件分发系统

local b = class()
function B:on_money_change(money)
	print(money,"B recive event")
end
EventSystem:on(Event.MoneyChanged,B.on_money_change,{target = B})
--定义回调函数和注册事件
local c = class()
function C:on_money_change(money)
	print(money,"C recive event")
end
EventSystem:on(Event.MoneyChanged,C.on_money_change,{target = C})

EventSystem:emit(Event.MoneyChanged,10)

关键点:

  1. 在事件派发的过程中订阅该事件,订阅还有优先级,需要小心处理排序问题
  2. 在事件派发的过程中取消订阅该事件,需要采用标记移除,不能直接移除
  3. 在事件派发的过程中又派发了该事件,如何确定事件派发完成
--注册接口实现
function EventSystem:on( event, func, params )
    --- ...
    local event_listener = self._listeners[event]
    params = params or {}
    local priority = params.priority or 0 --事件优先级设定
    local target = params.target
    --- ...
    local cb = {target = target, func = func, id = id, priority = priority}
    table.insert(event_listener.list, cb)
    id = id + 1
    if priority > 0 then
        event_listener.need_sort = true
        self:sort(event_listener)
    end
end
--排序事件
function EventSystem:sort( listener )
    if listener.need_sort == true and listener.emit_count == 0 then
    -- listener.emit_count == 0 当前事件没有处于派发状态
    --[[事件处于派发状态时不能进行优先级排序原因是可能会造成回调的重复触发。
       比如当前事件有4个回调 a, b, c, d,派发事件是顺序执行回调,当执行到第3个回调c时,如果在c回调中                  又注册了一个优先级最高的回调e,立刻排序的话,e插入到第一位,c会被挤到第4位,顺序执行到第4个回调时,导致c又被调用一次
    ]]
        table.sort(listener.list, function ( a, b )
            if a.priority == b.priority then
                return a.id < b.id
            else
                return a.priority > b.priority
            end
        end)
        listener.need_sort = false;
    end
end
--监听取消函数
function EventSystem:off( event, func, params )
    --- ...
    local event_listener = self._listeners[event]
    params = params or {}
    for i,cb in ipairs(event_listener.list) do
        if cb.func == func and cb.target == params.target then
            if event_listener.emit_count > 0 then
                -- 派发过程中只进行标记删除
                cb.need_remove = true
                event_listener.need_clean = true
            else
                table.remove(event_listener.list, i)
            end
            break;
        end
    end
end
--事件派发接口
function EventSystem:emit( event, ... )
    --- ...
    local event_listener = self._listeners[event]
    local interrupt = false
    local length = #event_listener.list
    -- 这里不能使用ipairs,确保不会触发在派发过程中注册的事件
    -- 只取当前已经注册的事件数量,如果在派发过程中再注册(调用了table.insert),本次派发也不会调用
    for i = 1, length do
        if interrupt == true then
            break
        end
        local cb = event_listener.list[i]
        if cb.func and cb.need_remove ~= true then
            event_listener.emit_count = event_listener.emit_count + 1
            if cb.target then
                interrupt = cb.func(cb.target, ...)
            else
                interrupt = cb.func(...)
            end
            event_listener.emit_count = event_listener.emit_count - 1
        end
    end
    self:sort(event_listener);
    self:clean(event_listener);
    return interrupt
end
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值