lua基于oopclass的属性节点类 和 集合类

本文介绍了一种用于管理属性和集合的类库实现。该类库提供了属性节点和集合节点两个核心类,支持属性的增删改查及集合成员的管理。适用于配置管理、规则定义等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

--[[----------------------------------------------------------------------------
--@ Descrption:   属性节点类库
--@ Changes:
-------------------------------------------------------------------------------]]

-- 引入面向对象的类机制
local oopclass = require("misc.oopclass")
local class = oopclass.class

-- 引入断言库
local assertlib = require("misc.assertlib")
local typeAssert = assertlib.typeAssert

-- 属性节点
local AttrNode = class()
AttrNode.__abstract = true

--[[
Function:   AttrNode.__attrInitialize
Description: 初始化节点属性
Parm:       self(object):对象本身
            source(table): 外部设置属性节点表
            attrs(table): 属性名称表
return:     NA
]]
AttrNode.__attrInitialize = function ( self, source, attrs )
    typeAssert(source, "table")
    typeAssert(attrs, "table")

    -- 记录合法的属性名称,用于修改属性
    self.__legal_attrs = attrs

    -- 将参数值记录到对象
    for _,para in ipairs(attrs) do
        if source[para] then
            self[para] = source[para]
        end
    end

    -- 只读属性表
    self.__readonly_attrs = {}
end

--[[
Function:   AttrNode.__checkAttrLegal
Description: 校验属性名合法性
Parm:       self(object):对象本身
            name(string): 属性名
return:     bool: 是否校验通过
]]
AttrNode.__checkAttrLegal = function ( self, name )
    typeAssert(name, "string")

    local legalAttrs = self.__legal_attrs

    -- 只有在合法列表中的属性才校验通过
    for _,attr in ipairs(legalAttrs) do
        if name == attr then
            return 
        end
    end

    assert(false, "attr name is illegal!")
end

--[[
Function:   AttrNode.setAttribute
Description:设置节点属性
Parm:       self(object):对象本身
            name(string): 属性名
            value(string): 属性值
return:     菜单节点对象
]]
AttrNode.setAttribute = function (self, name, value)
    typeAssert(name, "string")

    -- 属性类型支持三种类型:
    --  string, 例如 菜单id
    --  number, 例如 权限
    --  table, 例如 backendFile
    --  function, 例如 过滤函数
    --  nil, 保证可选的参数可以被设置为nil
    typeAssert(value, "string", "number", "table", "function", "nil")

    self:__checkAttrLegal(name)

    -- 只读属性,不允许修改
    for _,readOnlyAttr in ipairs(self.__readonly_attrs) do
        if readOnlyAttr == name then
            -- 直接返回
            return self
        end
    end

    self[name] = value

    -- 链式写法需要
    return self
end

--[[
Function:   AttrNode.getAttribute
Description:设置节点属性
Parm:       self(object):对象本身
            name(string): 属性名
return:     属性值
]]
AttrNode.getAttribute = function (self, name)
    typeAssert(name, "string")

    self:__checkAttrLegal(name)

    return self[name]
end

--[[
Function:   AttrNode.defineAttrReadOnly
Description:设置指定属性为只读
Parm:       self(object):对象本身
            name(string): 属性名
return:     属性值
]]
AttrNode.defineAttrReadOnly = function (self, name)
    typeAssert(name, "string")

    self:__checkAttrLegal(name)

    -- 记录属性到只读属性表
    table.insert(self.__readonly_attrs, name)

    -- 链式写法需要
    return self
end

--[[
Function:   AttrNode.searchCollection
Description:搜索节点的附属集合(collection), 例如 子菜单 和 功能区
Parm:       self(object):对象本身
            collection(table): 待搜索的集合
            func(function): 对于集合中的元素执行的操作
return:     NA
]]
AttrNode.searchCollection = function (self, collection, func)
    typeAssert(collection, "table")
    typeAssert(func, "function")

    local isloop = nil

    for index,item in ipairs(collection) do
        isloop = func(item, index)

        -- 后面不需要循环了
        if isloop == false then
            break
        end
    end
end

--[[
Function:   AttrNode.__attrToNVPair
Description: 将属性转换为 名值对 NVPair(name value pair): "name:value"
Parm:       self(object):对象本身
            name(string): 属性名
            splitter(string): name 和 value之间的分隔符
return:     NVPair(string)
]]
AttrNode.__attrToNVPair = function (self, name, splitter)
    typeAssert(name, "string")
    typeAssert(splitter, "string")

    self:__checkAttrLegal(name)

    local quotedName = string.format("%q", name)

    local ret = quotedName ..splitter

    local val = self[name]
    local typeOfVal = type(val)

    local valstr = "null"

    if typeOfVal == "nil" then
        valstr = "null"
    elseif typeOfVal == "string" then
        valstr = string.format("%q", val)
    elseif typeOfVal == "number" then
        valstr = tostring(val)
    -- 支持backendFile = {"xx", "yy"}的情况
    elseif typeOfVal == "table" then
        local cache = {}
        for _,v in ipairs(val) do
            if type(v) == "string" then
                local quotedStr = string.format("%q", v)
                table.insert(cache, quotedStr)
            end
        end
        local contentStr = table.concat(cache, ",")
        valstr = string.format("[%s]", contentStr)
    else
    end

    ret = ret .. valstr

    return ret
end

--[[
Function:   AttrNode.__getNVPairsofAttrs
Description: 将节点属性转换为字符串NVPair,缓存在表中
Parm:       self(object):对象本身
            splitter(string): name 和 value之间的分隔符
            attrs(table): 指定属性名集合,可选
return:     cache(table)
]]
AttrNode.__getNVPairsofAttrs = function (self, splitter, attrs)
    typeAssert(splitter, "string")
    typeAssert(attrs, "table", "nil")

    -- 如果未指定属性集合,确定为所有合法属性
    if not attrs then
        attrs = self.__legal_attrs
    end

    local cache = {}

    self:searchCollection(attrs, function ( item, index )
        -- every cache element is  name:value
        table.insert(cache, self:__attrToNVPair(item, splitter))    
    end)

    return cache
end

--[[
Function:   AttrNode.__nodeToJSON
Description: 将节点转换为JSON数据格式
Parm:       self(object):对象本身
            attrs(table): 指定属性名集合,可选
return:     json(string)
]]
AttrNode.__nodeToJSON = function (self, attrs)
    typeAssert(attrs, "table", "nil")

    local cache = self:__getNVPairsofAttrs(":", attrs)

    -- produce result: name1:value1, name2:value2
    local contentStr = table.concat(cache, ",")

    -- wrap content with bracket, get JSON
    local jsonStr = string.format("{%s}", contentStr)

    return jsonStr
end


-- 将此类返回
return AttrNode

 

 

--[[----------------------------------------------------------------------------
--@ Descrption:   集合类库
--@ Changes:
-------------------------------------------------------------------------------]]

-- 引入面向对象的类机制
local oopclass = require("misc.oopclass")
local class = oopclass.class
local instanceof = oopclass.instanceof


-- 引入属性节点类
local AttrNode = require("misc.attrnodeclass")

-- 引入断言库
local assertlib = require("misc.assertlib")
local typeAssert = assertlib.typeAssert

-- 集合节点
local CollectionNode = class(AttrNode)

--[[
Function:   CollectionNode.__init__
Description:实例初始化
Parm:       self(object):对象本身。
            itemProtoDesc(table): 集合成员原型描述,包括
                {
                    class -- 集合成员的类
                    keyName -- 集合成员的主键
                }
return:     无
]]
CollectionNode.__init__ = function ( self, itemProtoDesc )
    typeAssert(itemProtoDesc, "table")
    -- 集合成员的类
    typeAssert(itemProtoDesc.class, "table")
    -- 集合成员主键,用户查找、添加、删除等
    typeAssert(itemProtoDesc.keyName, "string")

    -- 集合成员的描述
    self.__itemProtoDesc = itemProtoDesc

    -- 集合成员的存储表 
    self.__itemSet = {}

    -- 集合成员静态修改器表
    self.__staticModFuncs = {}

    -- 集合成员动态修改器表
    self.__dynamicModFuncs = {}
end


--[[
Function:   CollectionNode.findItem
Description:按照主键值查集合成员
Parm:       self(object):对象本身。
            keyValue(string): 主键值
return:     targetObj, targetIndex : 目标对象, 目标对象下标
]]
CollectionNode.findItem = function ( self, keyValue )
    typeAssert(keyValue, "string")

    -- 查找
    local targetObj = nil
    local targetIndex = nil
    local keyName = self.__itemProtoDesc.keyName
    self:searchCollection(self.__itemSet, function ( item, index )
        if keyValue == item:getAttribute(keyName) then
            targetObj = item
            targetIndex = index
            return false
        end
    end)

    return targetObj, targetIndex
end

--[[
Function:   CollectionNode.addItem
Description:添加集合成员
Parm:       self(object):对象本身。
            itemTable(table): 集合成员原始数据表
return:     self
]]
CollectionNode.addItem = function ( self, itemTable )
    typeAssert(itemTable, "table")

    -- 类型要与原型一致
    local itemClass = self.__itemProtoDesc.class
    local itemObj = itemClass(itemTable)
    if not instanceof(itemObj, itemClass) then
        return self
    end

    -- key值异常保护
    local keyName = self.__itemProtoDesc.keyName
    local keyValue = itemObj:getAttribute(keyName)
    if not keyValue then
        return self
    end
    
    -- 将key属性设置对只读
    itemObj:defineAttrReadOnly(keyName)

    -- 新添加项的key值,不允许与现有表中项的key值重复!
    --  在表空间中, key表示的对象是唯一的, 在新添加表项时候, 需要检查冲突,
    --  只有在没有冲突的情况下, 才能添加成功。
    --  这种做法的考虑是,代码包化的背景下,addItem 分散在不同目录中,
    --  如果支持覆盖, 后添加者会将已有项覆盖掉,造成故障!!!
    --  对于正常的覆盖情况, 请先 调用 removeItem 然后 调用 addItem
    local sameKeyObj, sameKeyIndex = self:findItem(keyValue)
    -- 如果有重复,则报错
    if sameKeyObj then
        error("addItem keyName("..keyName..")'s keyValue("..keyValue..") conflict!")
    end

    -- 将新类型添加进去
    table.insert(self.__itemSet, itemObj)

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.removeItem
Description:删除指定集合成员
Parm:       self(object):对象本身。
            keyValue(string): 集合主键值
return:     self
]]
CollectionNode.removeItem = function ( self, keyValue )
    typeAssert(keyValue, "string")

    -- 按照主键,查找到集合成员,删除
    local targetObj, targetIndex = self:findItem(keyValue)
    if targetObj then
        table.remove(self.__itemSet, targetIndex)
    end

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.clearItem
Description:清空集合中所有成员
Parm:       self(object):对象本身。
return:     self
]]
CollectionNode.clearItem = function ( self, keyValue )
    typeAssert(keyValue, "string")

    -- 重新设置为空表
    self.__itemSet = {}

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.searchItem
Description: 遍历集合成员对象
Parm:       self(object):对象本身
            func(function): 对于集合成员执行的操作
return:     self
]]
CollectionNode.searchItem = function (self, func)
    typeAssert(func, "function")

    -- 遍历
    self:searchCollection(self.__itemSet, func)

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.loadConfig
Description: 以配置表形式加载规则
Parm:       self(object):对象本身
            configTable(table):配置表
return:     self
]]
CollectionNode.loadConfig = function (self, configTable)
    typeAssert(configTable, "table")

    -- 遍历configTable,设置到管理表中
    self:searchCollection(configTable, function ( item, index )
        self:addItem(item)
    end)

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.addModifier
Description: 添加加载器。
            加载器就是一个匿名函数,函数体中定义规则的修改语句(CRUD)。
            与loadConfig形成互补,支持分散注册规则(模块化要求),和修改已有规则(定制要求)。
            同一表对象,所有addModifier语句所属文件,在编译阶段拼接为一个文件 xxx_modifier.lua。
Parm:       self(object):对象本身
            modFunc(function):修改规则函数,无入参,无返回值
return:     self
]]
CollectionNode.addModifier = function (self, modFunc)
    typeAssert(modFunc, "function")

    table.insert(self.__staticModFuncs, modFunc)

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.loadModifier
Description: 执行所有的加载器函数。
            与addModifier接口逻辑配套,
            在require("xxx_modifier.lua")之后,调用此函数,完成规则修改功能。
Parm:       self(object):对象本身
return:     self
]]
CollectionNode.loadModifier = function (self)
    -- 执行所有加载器函数
    for _,modFunc in ipairs(self.__staticModFuncs) do
        modFunc()
    end

    -- 返回集合对象本身,支持链式写法
    return self
end

--[[
Function:   CollectionNode.runModifier
Description: 运行加载器,加载器定义与addModifier相同。
            与addModifier不同的是,此函数会将加载器函数,立刻执行,完成动态修改规则。
            说明: 
            1、loadConfig/addModifier&loadModifier 是为静态配置设计(第一次加载模块时),
            2、runModifier为动态配置设计,在任意文件中插入此语句,在将来运行到此文件,才加载规则。
Parm:       self(object):对象本身
            modFunc(function):修改规则函数,无入参,无返回值
return:     self
]]
CollectionNode.runModifier = function (self, modFunc)
    typeAssert(modFunc, "function")

    -- 遍历 已经执行过的 动态配置的修改器函数
    for _,modFuncCache in ipairs(self.__dynamicModFuncs) do
        -- 如果已经执行过,则不再执行, 避免 addItem 执行多次的情况
        if modFuncCache == modFunc then
            return self
        end
    end

    modFunc()

    table.insert(self.__dynamicModFuncs, modFunc)

    -- 返回集合对象本身,支持链式写法
    return self
end

-- 将此类返回
return CollectionNode

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值