Lua 类的封装

刚刚从C#和Java等强类型语言过渡到Lua等弱类型时,总觉得开发过程中有些别扭,而且面向对象的开发过程确实对开发过程中的业务逻辑更方便理解。为了方面广大开发者的习惯,Lua官方也给出了解决方案。

People = {name = "People", age = 12}
--这句是重定义元表的索引,就是说有了这句,这个才是一个类。
People.__index = People

--构造体,构造体的名字是随便起的,习惯性改为New()
function People:New(x, y)
    local obj= {} --初始化self,如果没有这句,那么类所建立的对象改变,其他对象都会改变
    setmetatable(obj, self) --将self的元表设定为Class
    self.name = x
    self.age = y
    return self --返回自身
end

--测试打印方法--
function People:test()
    print("x:>" .. self.name .. " y:>" .. self.age)
end

Lua中的 setmetatable (tableA, { __index = tableB }) 可以将 tableB 设置为 tableA 的原表,那么当 获取tableA中不存在的字段的时候,会去查找元表tableB中是否含有当前字段,有则返回数值。因此,我们可以通过上述代码模拟一下类。

当涉及当类的继承关系时候,应该怎么解决呢?

解决方法一:通过元表一层一层的指向父类,获取字段的时候一层一层的查找。
解决方法二:通过元表指向上一层父类的时候,将父类所有的字段Clone到当前元表中。
解决方法三:通过元表指向父类,并且当获取字段的时候将字段Clone到当前元表中,下次获取字段就可以直接获取数据。

云风大神给出了一个完美解决方案:解决方法三

--[[
模拟继承结构的基类
]]
local _class = {}

function Class(super)
    local class_type = {}
    class_type.ctor = false
    class_type.super = super
    class_type.New = function(...)
        local obj = {}
        do
            local create
            create = function(c, ...)
                if c.super then
                    create(c.super, ...)
                end
                if c.ctor then
                    c.ctor(obj, ...)
                end
            end

            create(class_type, ...)
        end

        setmetatable(obj, {__index = _class[class_type]})

        return obj
    end

    local vtbl = {}
    _class[class_type] = vtbl

    setmetatable(
        class_type,
        {
            __newindex = function(t, k, v)
                vtbl[k] = v
            end,
            --For call parent method
            __index = vtbl
        }
    )

    if super then
        setmetatable(
            vtbl,
            {
                __index = function(t, k)
                    local ret = _class[super][k]
                    vtbl[k] = ret
                    return ret
                end
            }
        )
    end

    return class_type
end

简单的对代码做一下分析:

  1. local People=Class(),返回一个Table(People)的内存指针指向class_type{},设置 class_type{} 的元表为 vtbl{} ,并在全局唯一变量_class中记录class_type的内存指针指向vtbl{} 。
  2. vtbl{} 设置 __newindex = function(t, k, v) ,当给tableA添加属性和方法的时候,调用 __newindex 指向的方法 function(t, k, v),这样 vtbl{} 中相当于存放了 People 的字段和方法。
  3. 实例化People的时候,需要调用PeopleInstance = People.New()方法,通过该方法返回Table(PeopleInstance)的内存指针指向obj {},设置 obj{} 的元表为_class[class_type],即为 vtbl{},因为 vtbl{} 中存放了 People 的字段和方法,PeopleInstance 即可获取到 People 的字段和方法。
  4. local Teacher=Class(People) , 类的创建过程与上述相同,当涉及当继承关系时候,Teacher的元表 vtbl{} 会指向 function(t, k) 方法,当获取Teacher中不存在的字段时候,会去_class[super]也就是People的元表vtbl{}中取值,同时给Teacher的元表 vtbl{} 赋值。

总结一下Lua类的封装:

  1. 官方给出的示例适用于没有继承关系的类,定义简单,使用过程也清楚明了。
  2. 云风的封装适用于有多层继承关系的情况,使用简单,性能和内存优化上都有较好解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值