Lua 创建一个有父类的class, 实现类继承机制的场景
Lua
--实现"把任意参数包装成表"
function cmd_PackArgs(argTab)
if argTab == nil then
return {};
elseif not (type(argTab) == "table") then
return { argTab };
end;
return argTab;
end;
-- 创建一个有父类的class
function cmd_CreateClass(className, super)
local cls;
if super then
cls = {};
cls.__super = super;
else
cls = {
---@param argTab table 参数需要封装成table
ctor = function(argTab) end;
};
end;
--给 cls 设置一个 __index 元方法,这是当访问 cls 的实例 object[k] 时,会调用的查找方法。
--self 通常表示访问的实例,k 是想访问的字段名。
cls.__index = function(self, k)
--rawget 是直接读取表 cls 的字段,不会触发元方法,避免死循环。这里尝试在本类 cls 中取字段 k。如果找到了,val 就不是 nil;否则是 nil。
local val = rawget(cls, k);
--如果本类没有找到该字段,并且存在父类 __super 才进入查找父类流程。current 从cls.__super(父类)开始。在 current(父类)中用 rawget 直接查找字段 k。如果找到(val 不再是 nil),跳出循环结束查找。如果没找到,继续向上查找父类的父类 current.__super。直到顶层父类为空或者找到成员为止
if val == nil and cls.__super then
local current = cls.__super;
while current and val == nil do
val = rawget(current, k);
current = current.__super;
end;
end;
return val;
end;
cls.className = function()
return cls.__className;
end;
cls.__className = className;
cls.__properties = {}; -- 属性列表
---@param data any 传递的参数
function cls:new(argTab, data)
---@param argTab table 参数需要封装成table
argTab = cmd_PackArgs(argTab);
--创建空表 o,用作实例的底层结构
local o = {};
--使用 cls 作为元表,设置元方法(其中包括上面你给的 __index),使实例支持类方法和继承属性访问。
local instance = setmetatable(o, cls);
--给实例添加 class 字段指向类本身,方便引用。
instance.class = cls;
--递归遍历该类及所有父类链上的 __properties 字段,将他们合并成一个总的 properties 表
local function mergeProperties(currentCls, properties)
if currentCls.__super then
mergeProperties(currentCls.__super, properties);
end;
if currentCls.__properties then
for k, v in pairs(currentCls.__properties) do
if properties[k] == nil then
properties[k] = v;
end;
end;
end;
end;
local mergedProperties = {};
mergeProperties(cls, mergedProperties);
--遍历 mergedProperties,给实例 instance 赋值属性
for k, v in pairs(mergedProperties) do
--如果实例当前没有该属性(instance[k] == nil),才赋值,继承特性。
if instance[k] == nil then
if type(v) == "table" then
--如果属性值是 table,执行深拷贝 DeepCopyTab_New(v),防止实例之间共享同一个子表,避免副作用
instance[k] = DeepCopyTab_New(v);
else
instance[k] = v;
end;
end;
end;
--假设类里有个 ctor 方法(构造函数),用来对实例进行进一步初始化。传入实例自身 instance 和两个参数 argTab、data
instance.ctor(instance, argTab, data);
return instance;
end;
return cls;
end;