15年11月写的这份代码,现在开源出来作为技术文档,希望大家能够看到帮助更多的人清晰的理解LUA元表。
1.首先,是我设计类的整体构造,解析给大家看,需要考虑对象创建出来不能够再去执行 new 等关键词,为此我为其添加了索引保护代码。
--[[
@格式
--]]
--[[
Proto = {
__index = <Proto>,
__metatable = <string>,
__add = <function>,
__tostring = <function>
<metatable> = {
__metatable = <string>,
__tostring = <function>
}
}
Class = {
__index = <function>,
__newindex = <function>,
__metatable = <string>,
__className = <string>,
__prototype = <Proto>,
__isInherit = <boolean>,
new = <function>,
super = <table>,
init = <function>,
<metatable> = <Proto>
}
instance = {
class = <Class>,
<metatable> = <Class>
}
--]]
2.接下来是真正的安全的类的代码。
--[[
@关键字 class
@参数 className <string>
@参数 super <table>
--]]
class = function (className)
local newProto = function ()
local Proto = setmetatable({}, {
__metatable = "Warning: can't change proto",
__tostring = function ()
return "proto"
end
})
Proto.__metatable = "Warning: can't change class"
Proto.__index = function (table, key) --保护数据
local protectList = {"__index", "__metatable", "__add", "__tostring"}
if table.__prototype then
for _, value in pairs(protectList) do
if key == value then
return nil
end
end
end
return Proto[key]
end
Proto.__add = function (first, second)
local checkSuper; checkSuper = function (super, second) --检测first.super是否存在second
for __, value in pairs(super) do
if value == second then
return true
end
if value.super then
if checkSuper(value.super, second) then --递归检测
return true
end
end
end
return false
end
local addSuper = function (first, second)
table.insert(first.super, second) --添加super
for key, value in pairs(second) do --添加方法
if not first[key] then
first[key] = value
end
end
return first
end
if type(second) ~= "table" then --检测类型
print("Error : super is not class")
return nil
end
if not second.__isInherit then --不可继承
print("Warning : [" .. second.__className .. "] is can't inherit")
return first
end
if first.super then --检测super是否存在
if checkSuper(first.super, second) then --检测second是否被继承
print("Warning : [" .. second.__className .. "] is already inherit")
return first
end
else
first.super = {}
end
if second.__prototype then --是否为class
first = addSuper(first, second)
else
for _, value in pairs(second) do
if value.__prototype then
first = addSuper(first, value)
else
print("Error : super is not class list")
return nil
end
end
end
return first
end
Proto.__tostring = function (table)
return "class: " .. table.__className
end
return Proto
end
local Proto = newProto() --构造proto
local Class = setmetatable({}, Proto)
Class.__prototype = Proto
Class.__metatable = "Error: can't change instance"
Class.__className = className
Class.__isInherit = true --可否被继承
Class.__index = function (table, key) --保护数据
local protectList = {"new", "super", "init", "__index", "__newindex", "__prototype", "__metatable", "__className", "__isInherit"}
if table.class then --是否为实例
for _, value in pairs(protectList) do
if key == value then
return nil
end
end
end
return Class[key]
end
Class.__newindex = function (table, key, value)
print("Error: can't change instance")
end
Class.new = function (...)
local init; init = function (class, ...)
local super = class.super
if super then
for _, value in pairs(super) do
init(value, ...) --递归初始化super
end
end
if class.init then
print(class.__className .. " init")
class:init(...)
end
end
local instance = {
class = Class
}
setmetatable(instance, Class)
init(instance.class, ...) --初始化实例
return instance
end
return Class
end
3.测试类及其对象
local A = class("A")
A.init = function(self)
print("A:init")
self.test = 0
end
A.Test = function(self)
print("Test", self.test)
end
local B = class("B") + A
B.init = function(self)
print("B:init")
print(tostring(self.super))
self.test = 1
end
B.Print = function(self, ...)
for _, value in ipairs(arg) do
print(value)
end
end
local b = B.new()
b:Test()
b:Print("a")
print(tostring(b.class))