欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > 分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)

分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)

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

一、前言

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

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

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

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

二、觀察者模式

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

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

三、事件分發(fā)系統(tǒng)

事件分發(fā)系統(tǒng)核心需要提供的功能主要包括以下幾個部分:

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

四、使用事件分發(fā)系統(tǒng)解決問題

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

A模塊只需要派發(fā)金幣修改事件,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模塊中派發(fā)金幣修改事件,當(dāng)前金幣為10
EventSystem:emit(Event.MoneyChanged, 10)

接下來會仔細解讀一下這個EventSystem事件分發(fā)系統(tǒng)的Lua實現(xiàn)代碼。

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

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

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

五、注冊監(jiān)聽事件接口

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參數(shù)表示要注冊監(jiān)聽的事件名稱,func參數(shù)表示當(dāng)事件發(fā)生時要觸發(fā)的回調(diào)函數(shù),params表示額外參數(shù),可以設(shè)置注冊監(jiān)聽的目標target(可以利用它反注冊所有與其相關(guān)的監(jiān)聽),也可以設(shè)置要注冊監(jiān)聽的優(yōu)先級,優(yōu)先級越高的越先執(zhí)行。

on方法的實現(xiàn)還是比較簡單的,主要就是將注冊的相關(guān)信息插入到event_listener表中,但是明明注冊的監(jiān)聽是有優(yōu)先級的,卻仍然只是調(diào)用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表示的是當(dāng)前的事件沒有處于派發(fā)狀態(tài),后面講到派發(fā)接口時會詳細解釋,這里讀者只需要知道其表示的含義即可。

事件處于派發(fā)狀態(tài)時不能進行優(yōu)先級排序原因是可能會造成回調(diào)的重復(fù)觸發(fā)。

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

六、反注冊事件監(jiān)聽接口

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
                -- 派發(fā)過程中只進行標記刪除
                cb.need_remove = true
                event_listener.need_clean = true
            else
                table.remove(event_listener.list, i)
            end
            break;
        end
    end
end

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

七、事件派發(fā)接口

function EventSystem:emit( event, ... )
    --- ...
    local event_listener = self._listeners[event]
    local interrupt = false
    local length = #event_listener.list
    -- 這里不能使用ipairs,確保不會觸發(fā)在派發(fā)過程中注冊的事件
    -- 只取當(dāng)前已經(jīng)注冊的事件數(shù)量,如果在派發(fā)過程中再注冊(調(diào)用了table.insert),本次派發(fā)也不會調(diào)用
    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方法負責(zé)派發(fā)一個事件,順序執(zhí)行event_listener中注冊的回調(diào)。事件的派發(fā)支持中斷,當(dāng)執(zhí)行某個回調(diào)時,如果這個回調(diào)返回了true則可以中斷當(dāng)前事件的派發(fā)。

值得一提的是,代碼通過對應(yīng)的event_listener.emit_count = event_listener.emit_count + 1event_listener.emit_count = event_listener.emit_count - 1來記錄事件的派發(fā)狀態(tài),當(dāng)emit_count > 0則表明事件還在派發(fā)過程中。當(dāng)emit_count == 0則表明事件派發(fā)完成。

不能使用event_listener.is_emiting = trueevent_listener.is_emiting = false代替的原因是如果在觸發(fā)的回調(diào)中又派發(fā)了事件,形成了遞歸,那么二次派發(fā)事件結(jié)束時會直接將event_listener.is_emiting置為flase,導(dǎo)致一次派發(fā)事件對應(yīng)的派發(fā)狀態(tài)被標記錯誤

八、更多

事件分發(fā)系統(tǒng)的完整源碼可以點擊這里查看,測試用例可以點擊這里查看
更多Lua相關(guān)的設(shè)計與使用,比如面向?qū)ο螅ùa中用到的class關(guān)鍵字),組件系統(tǒng),分模塊加載等等,可以查看GitHub倉庫LuaKit

以上就是分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)的詳細內(nèi)容,更多關(guān)于Lua 觀察者模式 構(gòu)建事件分發(fā)系統(tǒng)的資料請關(guān)注腳本之家其它相關(guān)文章!

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

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

巨人網(wǎng)絡(luò)通訊聲明:本文標題《分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)》,本文關(guān)鍵詞  分析,Lua,觀察者,模式,最佳,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)》相關(guān)的同類信息!
  • 本頁收集關(guān)于分析Lua觀察者模式最佳實踐之構(gòu)建事件分發(fā)系統(tǒng)的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    香蕉影视欧美成人| 国产全是老熟女太爽了| 美女的奶胸大爽爽大片| 久久综合国产精品| 卡一卡二国产精品| 波多野结衣福利| 日韩久久免费av| 日本亚洲三级在线| 国产三级国产精品| 精品久久久久久久一区二区蜜臀| 日本午夜一本久久久综合| 少妇被狂c下部羞羞漫画| 欧美日韩久久一区| 亚洲一区在线视频| 精品人妻在线视频| 欧美一区二区三区免费视频| 日韩av不卡一区二区| aaaaaav| 日韩西西人体444www| 日韩高清一级片| 中文字幕免费高清| 国产日产欧美一区二区三区| 国产高清一区日本| 色天天综合色天天久久| 一区二区免费看| 中文在线观看免费视频| 日韩一区二区不卡| 国产一区在线观看麻豆| 成年人网站在线观看视频| 国产精品国产三级国产aⅴ中文| 顶级嫩模精品视频在线看| 国产精品九九九九九九| 亚洲综合在线五月| 欧美bbbbb性bbbbb视频| 国产亲近乱来精品视频| 99re8在线精品视频免费播放| 欧美日韩黄色一区二区| 日韩国产精品久久| 天堂а√在线中文在线鲁大师| 日韩伦理电影网| 最新版天堂资源在线| 欧美大度的电影原声| 国产精品一区二区三区乱码| 色婷婷综合久久久久中文一区二区| 亚洲综合视频网| 尤物视频最新网址| 国产精品美女久久福利网站| 性生交大片免费看l| 2023国产精品视频| www.亚洲在线| 日韩精品影音先锋| 成人手机在线视频| 这里是久久伊人| 国产精品18久久久久久vr| 欧美性猛交xxxxxx富婆| 麻豆91小视频| 色婷婷在线视频观看| 午夜激情一区二区| 亚洲人做受高潮| 午夜天堂影视香蕉久久| 国产精品综合激情| 亚洲第一狼人社区| 在线免费看视频| 亚洲国产精品久久艾草纯爱| www.xx日本| 五月婷婷综合网| 卡通动漫亚洲综合| 人人狠狠综合久久亚洲| 青青青在线免费观看| 日韩av网站免费在线| 色8久久精品久久久久久蜜| 青娱乐精品视频在线| 91久久精品国产91性色tv| 麻豆一区二区三| 欧美视频在线观看一区| 国产一区二区在线视频| 欧美夫妻性生活| 成人黄动漫网站免费app| 日韩精品一区二区三区在线播放| 99久久国产综合精品麻豆| 久久综合九色综合97_久久久| 最新国产精品自拍| 国产精品情趣视频| 白白色免费视频| 亚洲国产精品久久人人爱| 中文字幕乱码av| 免费观看91视频大全| 欧美性猛交xxxx乱大交退制版| 国产成人自拍网| 日韩免费观看2025年上映的电影| 人妻激情偷乱视频一区二区三区| 亚洲国产经典视频| 成都免费高清电影| 亚洲在线视频一区| 色综合一个色综合| 国产精品小仙女| 久久一区二区视频| 素人fc2av清纯18岁| 亚洲成av人在线观看| 色菇凉天天综合网| 成人在线视频一区二区| 久久久精品人体av艺术| 一本色道久久综合亚洲精品图片| 亚洲国产精品视频| 精品污污网站免费看| 成人激情免费电影网址| 中文字幕乱码亚洲精品一区| 精品无码国产污污污免费网站 | 国产伦精品一区二区三区精品| 国产精品国产三级国产a| 精品丰满少妇一区二区三区| 老汉av免费一区二区三区| 日韩一级黄色大片| 黄色免费视频网站| 亚洲第一成人在线| 欧美日韩精品一区二区三区蜜桃| 波多野结衣亚洲| 国产精品二三区| 亚洲国产精品久| av综合在线播放| 专区另类欧美日韩| 久热这里有精品| 99精品久久99久久久久| 自拍偷拍国产精品| 91国模大尺度私拍在线视频| 99久久精品99国产精品| 亚洲精品老司机| 欧美探花视频资源| 午夜福利三级理论电影| 亚洲大片在线观看| 欧美一区二区三区色| 亚洲一级中文字幕| 激情图区综合网| 国产午夜精品一区二区 | 日本不卡视频在线| 欧美电影免费观看高清完整版在线观看 | 一区二区成人在线视频| 在线观看日产精品| 少妇熟女视频一区二区三区| 亚洲国产视频a| 欧美一区二区性放荡片| 国产熟妇久久777777| 国产一区二区三区精品视频| 国产欧美1区2区3区| 亚洲色婷婷一区二区三区| 精品人妻一区二区三| 亚洲国产日韩在线一区模特 | 日韩黄色免费网站| 欧美精品一区男女天堂| 黄色av片三级三级三级免费看| 国产91露脸合集magnet| 亚洲激情在线播放| 91精品国产欧美一区二区18| 一区二区精品免费| 国产91露脸合集magnet| 亚洲精品免费电影| 欧美一级久久久久久久大片| 欧洲美熟女乱又伦| 成人av一区二区三区| 亚洲电影中文字幕在线观看| 日韩一区二区免费在线电影| 国产精品1区2区3区4区| 99久久精品国产导航| 日本少妇一区二区| 国产欧美日韩精品a在线观看| 色婷婷久久99综合精品jk白丝| 老熟女高潮一区二区三区| 蜜桃久久av一区| 国产精品久久久久久亚洲毛片| 欧美亚洲国产怡红院影院| 韩国无码一区二区三区精品| 国产一本一道久久香蕉| 亚洲最大成人综合| 久久久久久亚洲综合| 色嗨嗨av一区二区三区| 人妻少妇一区二区| 不卡欧美aaaaa| 日韩av一区二区三区| 中文字幕一区二区三区在线观看| 欧美日本乱大交xxxxx| 99国产精品免费| 91精产国品一二三| 国产一区二区三区久久久| 亚洲影院免费观看| 中文字幕精品在线不卡| 欧美日本一区二区| 婷婷社区五月天| 无码人妻精品一区二区三区温州| 国产成人在线看| 日韩精品五月天| 亚洲视频你懂的| 精品国产露脸精彩对白| 在线观看91精品国产入口| 久久久久亚洲av成人无码电影| 91捆绑美女网站| 国产精品18久久久久久久网站| 性久久久久久久久| 亚洲视频中文字幕| 久久精品视频一区二区三区| 欧美日韩免费电影|