Lua事件分发机制实现方案小结

小结一

--[[
ModuleName :EventManager
Path : LuaPractice\EventManager.lua
Author :CJBKing
CreateTime :2019-11-11 18:17:08 
Description :
--]]

GlobalListenerMap={
--[[
	[target]={
	[type#key]=listenerList,
	}
--]]

}
local clsEvent={}
function clsEvent.Create(target,type,key,data)
	local o={
		target,
		type,
		key,
		data,
	}
	setmetatable(o,{__index=clsEvent})
	return o
end
function clsEvent:GetTarget() return self[1] end
function clsEvent:GetType() return self[2] end
function clsEvent:GetKey() return self[3] end
function clsEvent:GetData() return self[4] end

-----------------------------------------------------------------
function GenListenerId()
	local nextListenerId=0
	return function() 
		nextListenerId=nextListenerId+1
		return nextListenerId
	end
end
local genListenerId=GenListenerId()


local cacheEventTypeKey={
	--[eventType]={_KeyCnt=0,_KeyValue={[key]="eventType#Key"}}
}
-----这里当cacheEventTypeKey的某个eventType达到一定数时,会重置
-----比如EVENT_REMOVE_ENTITY的key是entityID,是动态变化的,这种类型的key随着程序的运行会很大
function GenIndex(eventType,key)
	local eventTypeMap=cacheEventTypeKey[eventType]
	local fEventType=tostring(eventType)
	local fKey=tostring(key)
	if not eventTypeMap then
		local f=string.format("%s#%s",fEventType,fKey)
		local keyValue={}
		keyValue[fKey]=f

	    eventTypeMap={}
		eventTypeMap._KeyCnt=1    --计数
		eventTypeMap._KeyValue=keyValue
		cacheEventTypeKey[fEventType]=eventTypeMap
		return f
	end
	local keyValue= eventTypeMap._KeyValue
	local f=keyValue[fKey]
	if f then  
		return f
	end

	local keyCnt=eventTypeMap._KeyCnt+1
	if keyCnt>1000 then     --如果事件类型大于1000
		keyValue={}
		eventTypeMap._KeyValue=keyValue
		keyCnt=1
	end
	f=string.format("%s#%s",fEventType,fKey)
	keyValue[fKey]=f
	eventTypeMap._KeyCnt=keyCnt		
	eventTypeMap._KeyValue=keyValue
	print(cacheEventTypeKey._KeyCnt)
	return f

end

function GetSubTableWithDefault(target,key)
	local value=target[key]
	if not value then
		value={}
		target[key]=value
	end
	return value
end

local clsListener={}
function clsListener.Create(Observer,Target,Type,Key,CallBack)
	local OId=genListenerId()
	local typeIndex=GenIndex(Type,Key)
	local listener={
		Observer,
		Target,
		Type,
		Key,
		CallBack,
		OId,
		typeIndex,
	}

	setmetatable(listener,{__index=clsListener})

	local typeListenerMap=GetSubTableWithDefault(GlobalListenerMap,Target)
	local listenerList=GetSubTableWithDefault(typeListenerMap,typeIndex)
	table.insert(listenerList,listener)

	if type(Observer)=="table" then
		local objListenerMap=GetSubTableWithDefault(Observer,"__eventListenerMap")
		objListenerMap[OId]=listener
	end
	return listener
end

function clsListener:GetObserver() return self[1] end

function clsListener:GetTarget() return self[2] end

function clsListener:GetType() return self[3] end

function clsListener:GetKey() return self[4] end

function clsListener:GetCallBack() return self[5] end

function clsListener:GetOId() return self[6] end

function clsListener:Handle(event)
	local callback=self:GetCallBack()
	callback(event)
	-- xpcall(callback,TracBack,event)
end
function clsListener:Remove()
	local typeIndex = self[7]
	if not typeIndex then
		----print("can not here.......")
		return
	end
	self[7] = nil

	local observer = self:GetObserver()
	if IsTable(observer) then
		local OId = self:GetOId()
		observer.__eventListenerMap[OId] = nil
	end

	local target = self:GetTarget()
	local typeListenerMap = GlobalListenerMap[target]
	if not typeListenerMap then
		return
	end

	local listenerList = typeListenerMap[typeIndex]
	local len = #listenerList
	if len == 1 and listenerList[1] == self then
		listenerList[1] = nil

		typeListenerMap[typeIndex] = nil
		if table.next(typeListenerMap) then
			GlobalListenerMap[target] = nil
		end
	else
		--local key = table.member_key(listenerList, self)  --- O(N)
		local key=nil
		for k,v in pairs(listenerList) do
			if v==self then
			 key=k
			end
		end
		if key then
			----使用最后一个元素覆盖并删除最后一个元素
			listenerList[key] = listenerList[len]
			listenerList[len] = nil
		end
	end
end
function TracBack(msg,level)
	-- print(msg,level)
end


function AddEventListener(observer, target, type, key, callback)
	return  clsListener.Create(observer, target, type, key, callback)
end

function RemoveListener(listener)
	if listener then 
		listener:Remmove()
	end
end

function RemoveEventListenerByType(observe,target,type,key)
	local typeListenerMap=GlobalListenerMap[target]
	if not typeListenerMap then
		return
	end
	local typeIndex=GenIndex(type,key)
	local listenerList=typeListenerMap[typeIndex]
	if not listener then
		return
	end
	local toDelListener = {}
	for _,listener in pairs(listenerList) do
		if listener:GetObserver()==observe then
			table.insert(toDelListener,listener)
		end
	end

	for _,listener in ipairs(toDelListener) do
		listener:Remove()
	end
end

function Dispatch(target, type, key, data)
	local targetListenerMap = GlobalListenerMap[target]
	if targetListenerMap then
		local allListenerList = nil
		local listenerList = targetListenerMap[GenIndex(type, key)]
			if listenerList then
				allListenerList = {}
				for _, listener in ipairs(listenerList) do
					table.insert(allListenerList, listener)
				end
			end
		if allListenerList then
			local event = clsEvent.Create(target, type, key, data)
			for _, listener in ipairs(allListenerList) do
				listener:Handle(event)
			end
		end
	end
end
---------------测试--------------------------
local  targetTest = {}
local function TestCallback(event)
	print(event:GetData())
end

-- for i=1,2000 do

--   AddEventListener(nil,TestModule,"Test","TestOne" .. i,TestCallback)
--   Dispatch(TestModule,"Test","TestOne" .. i,"this is Data"..i)
-- end

local TestModule=loadfile("E:/LuaProject/LuaPractice/Test.lua")()
--if TestModule then TestModule() else print("testModule is not Exist") end
AddEventListener(TestModule,TestModule,"Test","TestOne",TestModule.FuncCallBack)
Dispatch(TestModule,"Test","TestOne","this is Data")
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值