【网关开发】6.lua绑定委托(delegate)实现多播调用
背景
在程序开发过程中有时会遇到事件流的问题,某一个结果会触发A、B、C等一系列动作。需要将各种事件注册给委托类(Delegate)。Delegate类会依次触发注册的函数,完成相应的动作。
实现原理
lua中可以使用元表和队列的形式进行实现
实现细节
delegate.lua
local _M = { }
local _MT = { __index = _M }
local setmetatable = setmetatable
local table_remove = table.remove
-- _invoke_list 注册队列
-- _count 注册计数
function _M.new()
return setmetatable({ _invoke_list = { }, _count = 0 }, _MT)
end
-- __call 函数实现
function _MT:__call(...)
local _invoke_list = self._invoke_list
for i = 1, self._count do
_invoke_list[i](...)
end
end
-- 增加
local function add_delegate(self, cb, ...)
if not cb then
return self
end
local _invoke_list = self._invoke_list
local idx = self._count + 1
self._invoke_list[idx] = cb
self._count = idx
return add_delegate(self, ...) -- 递归添加
end
-- 会检查是否已经注册
local function add_delegate2(self, cb, ...)
if not cb then
return self
end
local _invoke_list = self._invoke_list
for i = 1, self._count do
if _invoke_list[i] == cb then
-- already exists, skip
return add_delegate2(self, ...)
end
end
local _invoke_list = self._invoke_list
local idx = self._count + 1
self._invoke_list[idx] = cb
self._count = idx
return add_delegate2(self, ...)
end
local function remove_delegate(self, cb, ...)
if not cb then
return self
end
local _invoke_list = self._invoke_list
for i = 1, self._count do
if _invoke_list[i] == cb then
table_remove(_invoke_list, i)
self._count = self._count - 1
break
end
end
return remove_delegate(self, ...)
end
local function is_empty(self)
return self._count == 0
end
_M.__add = add_delegate
_M.__sub = remove_delegate
_M.invoke = _MT.__call
_M.add_delegate = add_delegate
_M.add_delegate2 = add_delegate2
_M.remove_delegate = remove_delegate
_M.is_empty = is_empty
return _M
应用
-- 测试函数
local function delegate_test1(data)
ngx.log(ngx.INFO,"delegate_test1 "..data)
end
local function delegate_test2(data)
ngx.log(ngx.INFO,"delegate_test2 ".. data)
end
local function init()
watcher = delegate.new()
watcher:add_delegate2(delegate_test1)
watcher:add_delegate2(delegate_test2)
watcher("test")
end
测试
思考与总结
整个实现就是一个简单列表和对列表的操作,很好理解。结合场景实现一些广播功会更加方便。