【网关开发】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

测试

思考与总结

整个实现就是一个简单列表和对列表的操作,很好理解。结合场景实现一些广播功会更加方便。

posted @ 2023-01-28 15:53  zscbest  阅读(420)  评论(0编辑  收藏  举报