Lua面向对象 实现 超详细注释 实现构造函数,析构函数,只读类模板等功能
源码
-- 注意下面的代码可以拆开成多个文件使用,也可以放一起
-- Class.lua
local _class = {}
-- 将Source变成只读表并返回
function MakeTableReadOnly(Source)
local proxy = {}
local mt = {}
mt.__index = Source
mt.__newindex = function()
print("ReadOnly!")
end
setmetatable(proxy,mt)
return proxy
end
-- 返回class_type作为类模板,类模板可用来创建对象
function class(super)
local class_type = {}
-- ctor为构造函数
class_type.ctor = false
-- close为析构函数
class_type.close = false
-- super为父类,也是一个class_type
class_type.super = super
-- 类模板提供一个创建类实例的方法
class_type.new = function(...)
-- object为返回的类实例
local object = {}
-- create用于从父类一直递归的调用构造函数,c是class_type
local create
create = function(c,...)
if c.super then
create(c.super, ...)
end
if c.ctor then
c.ctor(object, ...)
end
end
-- 调用构造函数
create(class_type,...)
-- 构建元表
local mt = {}
-- 如果访问object中没有的对象,那么就访问_class[class_type],这样就实现了成员的继承
mt.__index = _class[class_type]
-- 析构函数
local close_function = function(...)
local destory
destory = function(c,...)
if c.close then
c.close(object,...)
end
if c.super then
destory(c.super,...)
end
end
destory(class_type, ...)
end
-- 当类实例被gc掉时,触发close_function
mt.__gc = close_function
-- 设置元表
setmetatable(object, mt)
return object
end
-- vtbl用于存放类模板的公用不可变成员,也就是类的成员(这里存放的是类中不可修改的,公用的部分,通常是函数或者常数)
local vtbl = {}
-- 类模板的成员不可修改
_class[class_type] = MakeTableReadOnly(vtbl)
-- 对类模板的新建值操作,实际上会存到vtbl中,可以实现函数的覆盖
setmetatable(class_type, {__newindex = function(t,k,v)
rawset(vtbl,k,v)
end})
-- 如果有父类
if super then
-- 如果访问类模板成员表中没有,就访问父类模板成员表
setmetatable(vtbl, {__index = function(t,k)
local res = _class[super][k]
-- 下面这行可以加可以不加,加上的话,这里会将父类的成员直接拷贝到子类中,之后再次访问的话效率会提高。但是热更新的情况下如果父类模板修改,子类不会修改。
-- rawset(vtbl,k,res)
return res
end})
end
-- 返回类模板
return class_type
end
-- Base.lua
-- 创建类模板
Base = class()
-- 这里不会触发class_type的__newindex元方法,因为class_type中已经有了
function Base:ctor(x)
print("Base:ctor")
-- 这里的self是类实例,而不是类模板,因为这个函数由上面的create调用,create传递的参数是object(类实例),根据:操作符,self就是object
self.x = x
end
-- 同理不会触发__newindex元方法
function Base:close(x)
print("Base:close")
end
-- 这里会触发class_type的__newindex元方法,将Hello方法加入到_class[class_type](也就是vtbl)中
function Base:Hello()
print("Base:Hello")
end
-- SubBase.lua
-- 创建SubBase 继承于 Base
SubBase = class(Base)
-- 同理不会触发__newindex元方法
function SubBase:ctor(x,y)
print("SubBase:ctor")
-- 这里的self是SubBase的类实例对象,由于create是递归的调用ctor方法,所以self中既有x也有y。
-- 为何要这样,通过ctor中使用self的这种方式,每个类实例对象的成员都是不同的,修改成员时不会相互影响
self.y = y
end
-- 同理不会触发__newindex元方法
function SubBase:close(x)
print("SubBase:close")
end
-- 这里实现了Hello函数的override,原理是vtbl绑定了__index元方法,只有__index元方法只有找不到的时候,才会返回父类成员
-- 由于class_type实现了__newindex方法,这里定义的函数会向vtbl中写入,从而实现函数的override
function SubBase:Hello()
print("SubBase:Hello")
end
-- 向vtbl中写入
function SubBase:SubHello()
print(self.x)
print(self.y)
end
-- Test.lua
-- 注意这里要使用.而不是:
-- 创建类实例
Test = Base.new(1)
Test2 = SubBase.new(1,2)
Test:Hello()
Test2:Hello()
Test2:SubHello()
-- 尝试修改类模板的成员
getmetatable(Test2)["__index"].Hello = function()
print("want to change!")
end