您的位置:首页 > 编程语言 > Lua

Lua实现OOP框架

2019-02-17 17:34 190 查看

Lua实现OOP框架

  • 面向对象的封装
  • 面向对象的继承和多态

  • 或许很多人在求职或者工作的过程中都会遇到类似,如何通过一个本身不支持OOP结构的语言来实现一个OOP结构的方案,在此整理了被人的一些实现方法

    实现思路

    基于Lua中table的元表metatable来实现

    语法糖

    在实现类结构之前需要先了解Lua中的语法糖:
    Lua中的函数都是有self传递进去的,相当于C++中的this
    例如

    local a =
    {
    x = 99
    }

    – 打印函数,注意这里要访问表a中的变量x,必须指明self.x或者a.x,不然会报错

    function a:Print()print("function a:test() " ..self.x)
    end

    – 想调用a的Print()函数,我们可以这样写,注意参数是a,否则调用出错

    a.Print(a)

    – 也可以这样写,即用:代替. 且不用传入参数a

    a:Print()

    可以理解为通过":"调用的话,默认会有self作为参数传递,且此方法更为简便

    Lua实现OOP的原理

    当访问Lua表中不存在的元素的时候,会触发Lua的一套查找机制

    举例说明:

    test =
    {
    }
    
    -- 访问表test中不存在的变量a
    print(test.a)

    此时的打印结果为nil,原因为test表中没有元素a,且test表没有元表metatable

    元表可以理解为一个备用查找表,假设表A的元表为B,那么在A中找不到的东西就会在B中继续查找
    举例说明:

    -- 表A
    A =
    {
    }
    
    -- 表B
    B =
    {
    a = 99
    }
    
    -- 给表B的元方法__index进行赋值
    B.__index = B
    
    -- 设置表B为表A的元表
    setmetatable(A,B)
    
    -- 再访问表A中不存在的变量a
    print(A.a)

    打印结果为:99
    查找过程:访问A.a时,先查看A表中是否有元素a,发现没有,但是发现A表有元表为B,则通过元表B的__index方法去查找,上述例子为B把自身赋值为自身的__index,如果__index为一个函数则调用函数获得其返回值,例子如下

    -- 表A
    A =
    {
    }
    
    -- 表B
    B =
    {
    a = 99
    }
    
    -- 给表B的元方法__index进行赋值,这里赋值为一个函数
    B.__index = function(table, key)
    print("在元表中访问了变量"..key)
    return 88
    end
    
    -- 设置表B为表A的元表
    setmetatable(A,B)
    
    -- 再访问表A中不存在的变量a
    print(A.a)

    打印结果:
    在元表中访问了变量a
    88

    总结元表的查找顺序

    步骤1.在表中查找,如果找到,返回该元素,找不到则继续步骤2
    步骤2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续步骤3
    步骤3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复步骤1、2、3;如果__index方法是一个函数,则调用该函数,并返回该函数的返回值

    面向对象的封装

    -- 类Class的声明,其实就是个table,这里有两个成员变量x,y
    Class =
    {
    x = 1,
    y = 2
    }
    
    -- 设置metatable的元方法__index,指向表Class自己
    Class.__index = Class
    
    -- 构造函数,叫什么名字无所谓,这里采用了C++的new名字
    function Class:new(x, y)
    print("Class:模拟构造函数new()")
    
    -- 新建一个对象,这样通过Class:new()函数创建的每一个实例都是独立的
    local tempObj = {}
    tempObj.x = x
    tempObj.y = y
    
    -- 设置新对象的metatable,谨记:这一步非常重要
    setmetatable(tempObj,Class)
    
    -- 返回这个新创建的对象
    return tempObj
    end
    
    -- 类的其他成员函数1
    function Class:Print()
    print("Class:Print()")
    print("x = "..self.x..", y = "..self.y)
    end

    面向对象的继承和多态

    -- 子类SubClass的声明,这里又声明了一个新的变量z
    SubClass =
    {
    z = 0
    }
    
    -- 设置元表为Class
    setmetatable(SubClass, Class)
    
    -- 设置metatable的元方法__index,指向表SubClass自己
    SubClass.__index = SubClass
    
    -- 构造函数
    function SubClass:new(x,y,z)
    
    print("模拟构造函数:SubClass")
    
    -- 先调用父类的构造函数,构造出一个父类的实例
    local tempObj = Class:new(x,y)
    
    -- 将该对象的元表指向SubClass,谨记:这步非常重要,一定不要弄错了,是SubClass
    setmetatable(tempObj,SubClass)
    
    -- 新属性z赋值,有了子类自己的数据,这样就是子类实例了
    tempObj.z = z
    
    return tempObj
    end
    
    -- 定义一个新的成员函数
    function SubClass:SubPrint()
    print("SubClass:SubPrint() x = "..self.x..", y = "..self.y..", z = "..self.z)
    end
    
    -- 重定义父类的函数Add(),注意:和父类的不同,这里是增加了2倍的val
    function SubClass:Add(val)
    print("SubClass:Add()")
    self.x = self.x + 2*val
    self.y = self.y + 2*val
    end

    参考https://blog.csdn.net/yzf279533105/article/details/80099358

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: