lua基于oopclass的属性节点类 和 集合类
--[[----------------------------------------------------------------------------
--@ 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
lua基于oopclass的属性节点类 和 集合类的更多相关文章
- [原创]cocos2d-x研习录-第二阶 概念类之节点类(CCNode)
节点类CCNode在基本概念中并不存在,它是为了建立基本概念之间的关联关系而抽象出来的中间辅助类.这个类在Cocos2D-x中极为重要,它为概念类之间搭建了一座宏伟的桥梁.它的继承关系图如下: ...
- cocos2dx[3.2](6) 节点类Node
与2.x相比,节点类Node的属性和功能做了大幅度的修改与增加. Node类是绝大部分类的父类(并不是所有的类,例如Director类是直接继承Ref类的),如Scene.Layer.Sprite以及 ...
- 初探JavaScript(一)——也谈元素节点、属性节点、文本节点
Javascript大行其道的时候,怎么能少了我来凑凑热闹^_^ 基本上自己对于js的知识储备很少,先前有用过JQuery实现一些简单功能,要论起JS的前世今生,来龙去脉,我就一小白.抱起一本< ...
- Labview中的属性节点
获取(读取)和/或设置(写入)引用的属性.通过属性节点对本地或远程应用程序实例.VI或对象获取或设置属性和方法也可通过属性节点访问LabVIEW类的私有数据. 属性节点可自动调整为用户所引用的对象的类 ...
- C# 读取xml节点类容
这是一个测试节点类容的获取 这是控制台代码部分 注意的应用文件 :using.system.Xml using System; using System.Collections.Generic; us ...
- MyBatis之基于XML的属性与列名映射
上一博客主要是对单表的增删改查,比较简单,而且每个属性与table表的列都是一一对应名字也一样,今天主要学习属性与table表列名不一致的处理,主要有两种一是属性与列名不一致,二是枚举的情况,这里暂时 ...
- 【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态
一.简介 Lua是一门非常强大.非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言.但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是 ...
- Ignite集群管理——基于静态IP的节点发现
Ignite作为分布式内存,集群管理必不可少,Ignite支持基于组播,静态IP,Zookeeper,JDBC等方式发现节点,本文主要介绍基于静态IP的节点发现. 两个最重要的TCP通信设置类: 1. ...
- 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- electron打包之真的恶心
用electron-packager进行打包 这个模块的文档写的真的垃圾 1.先看看首页的参数介绍 就是说必选参数就是源码路径和app名字和--platform还有--arch咯,而且源码路径也没说是 ...
- [2017-8-02]Android Learning Day9
Layout动画效果 为布局添加简单的动画效果 public class MainActivity extends AppCompatActivity { @Override protected vo ...
- [WC2011]最大XOR和路径(贪心+线性基)
题目大意:给一张无向图,求一条1-n的路径,是路径边权的异或和最小. 题解 这道题的思路很妙,首先我们可以随便找出一条从1到n的路径来,然后我们可以选一些环. 其实不管这个环和这条路径有怎样的关系,我 ...
- bzoj4383(拓扑排序)
给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r-1],a[ ...
- RHEL7 下双网卡绑定做主备(冗余)
应用环境:在生产环境中,为了提高网络容错或吞吐量,一般服务器都会采取多网卡绑定的策略(此处只讲主备模式). 在RedHat 6.x下一般叫网卡做“bond”,在7.x版本中改名叫“Team”. 测试 ...
- Linux下设置VSCode为默认的文本编辑器
解决方法 执行一下命令 xdg xdg-mime default code.desktop text/plain Debian alternatives system sudo update-alte ...
- vue $emit 用法
1.父组件可以用props传递给子组件. 2.子组件可以利用$emit触发父组件事件. vm.$emit('父组件方法',参数); vm.$on(event,fn); $on监听event事件后运行f ...
- Java 对远程文件的操作
首先添加jar <dependency> <groupId>jcifs</groupId> <artifactId>jcifs</artifact ...
- Gym 101911E "Painting the Fence"(线段树区间更新+双端队列)
传送门 题意: 庭院中有 n 个围栏,每个围栏上都被涂上了不同的颜色(数字表示): 有 m 条指令,每条指令给出一个整数 x ,你要做的就是将区间[ x第一次出现的位置 , x最后出现的位置 ]中的围 ...
- 高级组件——工具栏JToolBar
import javax.swing.*; import java.awt.*; public class Demo extends JFrame { public Demo() { setTitle ...