消息模式/事件監聽 lua

消息模式有三個主要對象,分別是:

  1. 消息監聽者:監聽消息
  2. 消息中心:存儲、刪除消息
  3. 消息發送者:發送廣播
    看下面的圖,大概對每個部分的職能能夠清楚的瞭解:
    在這裏插入圖片描述

下面是主要代碼:

Msg.lua

相當於消息中心,對所有消息進行處理
其中Remove的三個參數支持多種方式的移除消息方式,具體的可以參考代碼邏輯進行理解和修改

Msg = {}

Msg.init = function()
	--[[
		msgmap = {
			msgId = {
				{instance1, func1},
				{instance2, func2}
			}
		}
	]]
	Msg.msgmap = {}
end

--@desc 添加綁定事件
--@arg  ... msgId, instance, func
--@arg  msgId 消息Id
--@arg  func 消息執行函數
Msg.Add = function(instance, msgId, func)
	local msgObj = {instance, func}
	if not Msg.msgmap[msgId] then
		Msg.msgmap[msgId] = {msgObj}
	else
		local list = Msg.msgmap[msgId]
		for _, obj in pairs(list) do
			if obj[1] == instance and obj[2] == func then
				return
			end
		end
		table.insert(Msg.msgmap[msgId], msgObj)
	end
end

--@desc 移除綁定事件
--@arg  msgId 消息Id
--@arg  instance 監聽實例
--@arg  func 消息執行函數
Msg.Remove = function(msgId, instance, func)
	if msgId then
		if not instance and not func then
			Msg.msgmap[msgId] = nil
		else
			local list = Msg.msgmap[msgId]
			Msg._remove(list, instance, func)
		end
	else
		for id, list in pairs(Msg.msgmap) do
			Msg._remove(list, instance, func)
		end
	end
end
Msg._remove = function(list, instance, func)
	if not list then
		return
	end
	for index, msgObj in pairs(list) do
		if instance and func then
			if msgObj[1] == instance and msgObj[2] == func then
				table.remove(list, index)
			end
		elseif instance and not func then
			if msgObj[1] == instance then
				table.remove(list, index)
			end
		elseif not instance and func then
			if msgObj[2] == func then
				table.remove(list, index)
			end
		end
	end
end

--@desc 發送事件
--@arg  msgId 消息Id息
Msg.Send = function(msgId, ...)
	local list = Msg.msgmap[msgId]
	if list then
		for _, msgObj in pairs(list) do
			if msgObj[2] then
				msgObj[2](...)
			end
		end
	end
end

Msg.init()
return Msg

MsgId.lua

用於存儲消息Id的腳本

MsgId = {}

MsgId.DOG_RUN = "DOG_RUN"

-- 簡單實現個只讀功能
setmetatable(MsgId, {__newindex = function()
	print("new id must add in MsgId.lua")
end})

test.lua

其中的dog1,dog2,dog3,相當於消息監聽者,通過Msg.Add函數監聽消息;Msg.Send相當消息發送者,廣播對應的消息id

--[[
	class 函數是自己實現的一個聲明類的函數
]]
local Dog = class("Dog", nil)

local dog1 = Dog.new()
local dog2 = Dog.new()
local dog3 = Dog.new()
dog3.AddMsg = function(self)
	Msg.Add(self, MsgId.DOG_RUN, function(...)
		print("dog3 跑, 通過外部添加監聽", ...)
	end)	
end

Msg.Add(dog1, MsgId.DOG_RUN, function(...)
	print("dog1 跑, 通過外部添加監聽", ...)
end)
Msg.Add(dog2, MsgId.DOG_RUN, function(...)
	print("dog2 跑, 通過外部添加監聽", ...)
end)
dog3:AddMsg()

Msg.Send(MsgId.DOG_RUN, "-> test 事件參數")
print("------------------------------------------")
Msg.Remove(MsgId.DOG_RUN, dog2)
Msg.Send(MsgId.DOG_RUN, "-> test 事件參數")
print("------------------------------------------")

--[[ 輸出信息:
dog1 跑, 通過外部添加監聽	-> test 事件參數
dog2 跑, 通過外部添加監聽	-> test 事件參數
dog3 跑, 通過外部添加監聽	-> test 事件參數
------------------------------------------
dog1 跑, 通過外部添加監聽	-> test 事件參數
dog3 跑, 通過外部添加監聽	-> test 事件參數
------------------------------------------
[Finished in 0.1s]
]]

在test腳本中,

  1. 3個監聽者分別監聽了MsgId.DOG_RUN消息
  2. Msg.Send(MsgId.DOG_RUN, "-> test 事件參數")進行了一次廣播
  3. Msg.Remove(MsgId.DOG_RUN, dog2)將消息中心dog2MsgId.DOG_RUN消息移除
  4. Msg.Send(MsgId.DOG_RUN, "-> test 事件參數")又進行了一次廣播,因爲之前有移除過dog2的對應消息,所以再次輸出中沒有dog2的輸出。

更進階的還包括消息的優先級等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章