校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 分析Lua觀察者模式最佳實踐之構建事件分發系統

分析Lua觀察者模式最佳實踐之構建事件分發系統

熱門標簽:免費門店地圖標注注冊入駐 艾比利外呼系統 昆明電話外呼系統好么 衡水外呼線路解決 杞縣地圖標注app 電話機器人每天搜索多少次 陜西便宜電銷機器人軟件 外呼系統一天耗費多少流量 海口智能語音電銷機器人好用嗎

一、前言

試想這樣一個問題,當某個事件發生時,比如在游戲中A模塊修改了用戶的金幣數,而B模塊和C模塊提供的功能都依賴于用戶的金幣數,那么,A模塊在修改金幣數的同時,就需要通知B模塊和C模塊。常規的方法就是A模塊持有B模塊和C模塊的對象,然后分別通過調用對象接口的方式告訴它們,“嘿,我修改了用戶的金幣數,改成了10金幣”。

但這樣就帶來了許多問題:

  • A模塊引用了B模塊和C模塊,耦合嚴重
  • A模塊修改金幣數的方法中調用了B,C模塊的方法,當這兩個模塊發生變化時(比如B模塊接收金幣數的接口名稱改變了,或是C模塊不再需要知道金幣數改變了),A模塊也要修改
  • 當又出現一個D模塊也需要知道金幣數的變化時,同樣需要修改A模塊以適應這種需求

為了解決上面的問題,我們自然想到了觀察者模式。

二、觀察者模式

這里簡單說一下什么是觀察者模式:定義對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者(稱之為觀察者)都會接收到通知并自動更新。

觀察者模式的好處是,對象之間是松耦合的,當一個對象改變狀態時,它并不需要知道自己的觀察者是誰,只需要發布通知即可。任何時候都可以增加或刪除觀察者,不會影響到發布通知的對象。而事件分發系統就是觀察者模式的一個具體實現

三、事件分發系統

事件分發系統核心需要提供的功能主要包括以下幾個部分:

  • 當一個對象發生改變時,可以認為此時產生了一個事件,提供一個派發事件的接口,以通知所有的觀察者
  • 需要提供注冊監聽事件的接口,以讓觀察者可以訂閱自己需要接收的事件
  • 還需提供反注冊監聽事件接口,以讓觀察者可以取消自己的訂閱
  • 最好還能在訂閱的時候設置優先級,優先級越高的可以越先被通知

四、使用事件分發系統解決問題

首先,來看看使用事件分發系統處理上面提到的問題,會是什么樣的效果。

A模塊只需要派發金幣修改事件,B,C模塊只需要訂閱金幣修改事件,之后便可以收到通知了。是不是很簡單呢

local B = class()
function B:on_money_change( money )
    print(money, "B receive event")
end
-- 訂閱金幣修改事件
EventSystem:on(Event.MoneyChanged, B.on_money_change, {target = B})

local C = class()
function C:on_money_change( money )
    print(money, "C receive event")
end
EventSystem:on(Event.MoneyChanged, C.on_money_change, {target = C})
-- 在A模塊中派發金幣修改事件,當前金幣為10
EventSystem:emit(Event.MoneyChanged, 10)

接下來會仔細解讀一下這個EventSystem事件分發系統的Lua實現代碼。

實現事件分發系統時,需要小心一些特殊情況,比如有以下幾個坑,讀者可以留意一下代碼中對這幾個坑的處理

  • 在事件派發的過程中訂閱該事件,訂閱還有優先級,需要小心處理排序問題
  • 在事件派發的過程中取消訂閱該事件,需要采用標記移除,不能直接移除
  • 在事件派發的過程中又派發了該事件,如何確定事件派發完成

為了便于講解,下面的代碼省略了一些非關鍵性的代碼,用--- ...代替。

五、注冊監聽事件接口

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

on方法中event參數表示要注冊監聽的事件名稱,func參數表示當事件發生時要觸發的回調函數,params表示額外參數,可以設置注冊監聽的目標target(可以利用它反注冊所有與其相關的監聽),也可以設置要注冊監聽的優先級,優先級越高的越先執行。

on方法的實現還是比較簡單的,主要就是將注冊的相關信息插入到event_listener表中,但是明明注冊的監聽是有優先級的,卻仍然只是調用table.insert將信息插入到表的末尾,這是為什么呢?讀者可以先留意一下,后面會有詳細解釋。
還需要格外注意的是sort方法

function EventSystem:sort( listener )
    if listener.need_sort == true and listener.emit_count == 0 then
        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

可以看到sort方法必須在listener.emit_count == 0時才會進行排序,listener.emit_count == 0表示的是當前的事件沒有處于派發狀態,后面講到派發接口時會詳細解釋,這里讀者只需要知道其表示的含義即可。

事件處于派發狀態時不能進行優先級排序原因是可能會造成回調的重復觸發。

比如當前事件有4個回調 a, b, c, d,派發事件是順序執行回調,當執行到第3個回調c時,如果在c回調中又注冊了一個優先級最高的回調e,立刻排序的話,e插入到第一位,c會被擠到第4位,順序執行到第4個回調時,導致c又被調用一次。

六、反注冊事件監聽接口

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

off方法用于取消事件監聽,當事件未處于派發過程中時,直接調用table.remove移除注冊信息即可,但當事件處于派發過程中時,不能直接移除,只能先進行標記。
在事件處于派發過程中時不能直接移除的原因是可能導致遺漏觸發某些回調,比如當前事件有5個回調 a, b, c, d, e,順序執行到第3個回調c時,如果在c回調中調用了off方法取消自己的監聽,此時直接移除c的話,會導致d回調移動到第3位,e移動到第4位,順序執行到第4個回調時,調用的是e而遺漏了d。

七、事件派發接口

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

emit方法負責派發一個事件,順序執行event_listener中注冊的回調。事件的派發支持中斷,當執行某個回調時,如果這個回調返回了true則可以中斷當前事件的派發。

值得一提的是,代碼通過對應的event_listener.emit_count = event_listener.emit_count + 1event_listener.emit_count = event_listener.emit_count - 1來記錄事件的派發狀態,當emit_count > 0則表明事件還在派發過程中。當emit_count == 0則表明事件派發完成。

不能使用event_listener.is_emiting = trueevent_listener.is_emiting = false代替的原因是如果在觸發的回調中又派發了事件,形成了遞歸,那么二次派發事件結束時會直接將event_listener.is_emiting置為flase,導致一次派發事件對應的派發狀態被標記錯誤

八、更多

事件分發系統的完整源碼可以點擊這里查看,測試用例可以點擊這里查看
更多Lua相關的設計與使用,比如面向對象(代碼中用到的class關鍵字),組件系統,分模塊加載等等,可以查看GitHub倉庫LuaKit

以上就是分析Lua觀察者模式最佳實踐之構建事件分發系統的詳細內容,更多關于Lua 觀察者模式 構建事件分發系統的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:
  • SpringBoot+Redis執行lua腳本的方法步驟
  • 如何使用Vim搭建Lua開發環境詳解
  • Lua中三種循環語句的使用講解
  • Lua中的變量與賦值方法
  • Android事件分發機制(上) ViewGroup的事件分發
  • 詳解EventDispatcher事件分發組件
  • Android View 事件分發機制詳解
  • PHP中常用的三種設計模式詳解【單例模式、工廠模式、觀察者模式】
  • 淺談發布訂閱模式與觀察者模式

標簽:海口 宿遷 臨滄 營口 西寧 昌都 南京 泰安

巨人網絡通訊聲明:本文標題《分析Lua觀察者模式最佳實踐之構建事件分發系統》,本文關鍵詞  分析,Lua,觀察者,模式,最佳,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《分析Lua觀察者模式最佳實踐之構建事件分發系統》相關的同類信息!
  • 本頁收集關于分析Lua觀察者模式最佳實踐之構建事件分發系統的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    韩国精品在线观看| 婷婷综合在线观看| 成人精品小蝌蚪| 日本一区二区三区电影| 国产一区美女在线| 久久久久久久国产精品影院| 国产在线一区二区| 国产精品污www在线观看| k8久久久一区二区三区| 亚洲自拍偷拍欧美| 欧美精品精品一区| 激情五月激情综合网| 国产精品午夜免费| 欧美性xxxxx极品少妇| 日本成人超碰在线观看| 久久理论电影网| 91女人视频在线观看| 一区二区不卡在线视频 午夜欧美不卡在 | 国产白丝精品91爽爽久久| 亚洲国产精品成人综合| 欧美做爰猛烈大尺度电影无法无天| 亚洲午夜久久久久久久久电影网| 91麻豆精品91久久久久同性| 国产成人日日夜夜| 尤物在线观看一区| 日韩欧美国产综合在线一区二区三区 | 欧美一区永久视频免费观看| 韩国三级在线一区| 亚洲图片另类小说| 欧美va在线播放| 91丨porny丨首页| 欧美aaaaa成人免费观看视频| 国产日韩精品一区| 欧美日韩国产一级| 成人av高清在线| 美国av一区二区| 亚洲天堂a在线| 精品国产免费人成在线观看| 色狠狠色狠狠综合| 国产精品18久久久久久久久| 亚洲图片欧美色图| 日本一区二区三区四区在线视频| 在线播放/欧美激情| 91丨九色丨国产丨porny| 久久精品久久久精品美女| 亚洲色欲色欲www在线观看| 亚洲精品在线观看视频| 欧美日韩国产电影| 91丨porny丨户外露出| 国产一区二区三区四区五区入口 | 亚洲综合丝袜美腿| 中文字幕va一区二区三区| 日韩免费看的电影| 欧美最猛黑人xxxxx猛交| 成人h动漫精品一区二| 久久精品国产精品亚洲红杏| 亚洲综合激情网| 亚洲欧美自拍偷拍色图| 久久久91精品国产一区二区精品| 欧美一卡二卡三卡| 欧美精品aⅴ在线视频| 91麻豆蜜桃一区二区三区| 国产激情精品久久久第一区二区| 麻豆精品新av中文字幕| 亚洲综合视频在线| 亚洲免费成人av| 国产精品久久久99| 国产精品久久久久毛片软件| 国产亚洲欧美激情| 久久综合五月天婷婷伊人| 日韩一区二区三| 777奇米四色成人影色区| 日本韩国欧美在线| 色综合av在线| 日本韩国欧美一区| 在线中文字幕一区二区| 欧美影视一区在线| 欧洲一区在线观看| 欧美色图在线观看| 欧美另类videos死尸| 欧美日韩亚洲综合在线| 欧美艳星brazzers| 欧美日本在线观看| 欧美一区二区黄| 精品乱码亚洲一区二区不卡| 2024国产精品| 国产欧美日本一区视频| 国产精品天干天干在线综合| 国产精品福利影院| 亚洲欧洲一区二区在线播放| 亚洲女子a中天字幕| 亚洲综合一区在线| 日韩av在线播放中文字幕| 蜜桃视频一区二区| 国产精品一区免费视频| hitomi一区二区三区精品| 91免费精品国自产拍在线不卡| 91免费视频观看| 欧美日韩五月天| 日韩精品专区在线| 国产欧美日韩在线| 亚洲蜜桃精久久久久久久| 午夜久久久久久久久| 久久99国产精品久久99| 成人午夜电影久久影院| 色狠狠av一区二区三区| 91精品蜜臀在线一区尤物| 欧美精品一区二区精品网| 国产精品视频第一区| 亚洲一区二区三区不卡国产欧美| 青青草国产精品97视觉盛宴| 国产白丝精品91爽爽久久| 欧美午夜一区二区三区| 精品国产一区二区三区久久久蜜月| 国产精品视频免费看| 午夜欧美电影在线观看| 国产精品自拍毛片| 欧美三级日韩在线| 国产欧美va欧美不卡在线| 一区二区在线观看免费| 精品写真视频在线观看| 99riav一区二区三区| 欧美一区午夜视频在线观看| 国产精品女同互慰在线看| 日韩精品一级中文字幕精品视频免费观看 | 中文字幕欧美区| 亚洲va欧美va人人爽| 懂色中文一区二区在线播放| 欧美日韩你懂的| 国产精品久久久久毛片软件| 日韩精品电影在线观看| 色综合中文字幕国产| 5566中文字幕一区二区电影| 国产精品动漫网站| 美国毛片一区二区| 欧美色网一区二区| 亚洲你懂的在线视频| 国内久久精品视频| 制服.丝袜.亚洲.中文.综合| 亚洲人吸女人奶水| 国产成人精品在线看| 日韩欧美在线影院| 天堂久久一区二区三区| 色欧美88888久久久久久影院| 久久精品一区二区三区av| 日本免费在线视频不卡一不卡二| 色综合视频在线观看| 国产欧美综合在线观看第十页| 日本在线不卡视频| 欧美三级三级三级爽爽爽| 亚洲天堂网中文字| 成人黄色小视频在线观看| 精品国产一区二区三区不卡| 日韩精品亚洲一区二区三区免费| 91久久精品一区二区三| 国产精品欧美经典| 福利一区二区在线| 国产欧美日本一区二区三区| 韩国一区二区三区| 精品卡一卡二卡三卡四在线| 日韩电影免费在线看| 在线播放91灌醉迷j高跟美女| 亚洲综合在线第一页| 欧美网站大全在线观看| 亚洲一区在线观看免费| 欧洲中文字幕精品| 亚洲国产综合91精品麻豆| 日本精品一级二级| 亚洲大片在线观看| 在线不卡a资源高清| 午夜激情一区二区三区| 制服丝袜中文字幕一区| 日本91福利区| 精品粉嫩aⅴ一区二区三区四区| 国模套图日韩精品一区二区 | 一区二区三区欧美久久| 91免费视频网| 亚洲午夜成aⅴ人片| 欧美精品第1页| 蜜臀久久99精品久久久久久9| 日韩久久精品一区| 国产一区二区三区四区五区美女 | 久久精品一二三| 成人性色生活片| 亚洲丝袜精品丝袜在线| 在线观看亚洲精品| 免费欧美在线视频| 久久精品人人做| 99精品国产一区二区三区不卡| 一区二区在线免费| 欧美一区二区成人| 国产一区二区女| 中文字幕在线不卡一区| 欧美综合在线视频| 精品一区二区av| 国产精品色呦呦| 欧美性色黄大片| 国内不卡的二区三区中文字幕| 亚洲欧洲性图库| 91麻豆精品久久久久蜜臀|