• lua下的简单OO实现


    笔者学习了当前(文末各文献)lua下的各种OO实现方法。略作笔记。
    也提出了一些自己的想法。主要还是记录供将来着之参考。
     

    1.概述

     
    首先【2】PIL第二版中给出了OO的基于table的实现方式,核心方法是基于setmetatable方法。当检索到自己未提供的方法时,递归检索父类。文【5】给出了给出了基于闭包的实现方法。文【6】给出了is-a的方法的实现。文7给出了clone的实现。文【8】测试了基于table和closure的两种方案,并给出结论。
    文【1】存储父类方法到本地能够减少调用回溯的开销,并给出了基于closure的分离类和实例的方法。
     
    综合来看1是较好的,但是1也有其不足,比如祖父类的一个方法可能孙子类需要,父类不需要,可以跨代存储。
    但是这些都是看应用环境的。
     
    本着学习和应用的目的,笔者逐一实现以上各种方案。逐步改版。耗费大概2日。
    lua下想实现OO还是,其一项目中多个模块有类似功能,可以抽象出来成为基类(别的方法也行),其二有几个大模块,功能类似于是跑车,出租车,公交车的功能,使用OO的思想来设计能够更大化DRY,维护更方便。
    主要还是以锻炼LUA下的调试能力,学习lua下OO为主吧。
     
    目前只是实现类的几个基本功能:1.继承、2.多态。以达到DRY复用的效果。
    未实现:构造、析构函数。多重继承、接口等等
     
     

    2.主要的知识点

    1.元表
    table类型都有一个元表。在元表中,定义默认方法的实现,比如add=>+,sub=》-。
    这里用到了index和newindex
    "index": 索引 table[key]时,当table不是表或者表中无该key 时触发;换句话说就是当调用父类方法的时候在这里操作。他可以是一个表(继续调用),也可以是一个这样的函数
    function __index(table,key) return functionbody end
    同理newindex。当table[key]=value时,当table不是表或者表中无该key 时触发,无key也就是说可以是这样的情况,创建新的属性或者方法。
    function __newindex(table,key,value) table[key]=value end
    2. setmetatable (table, metatable)
    给指定表设置元表。 如果 metatable 是 nil, 将指定表的元表移除。 如果原来那张元表有 "__metatable" 域,抛出一个错误。
     

    3.历次实现

    第一版;new的时候将自己作为新对象的元表。

    ---------------------------------------------------------------------------------------
    baseclass={}
    function baseclass:new (o)
          o = o or {}   -- create object if user does not provide one
          o.super=baseclass --  keep base class
          setmetatable(o, self)
          self.__index = self
          return o
    end
    
    function baseclass:classname()
    return  "baseclass"
    end
    
    function baseclass:ctor()
        return "baseclassctor"
    end
    
    
    a1class=baseclass:new()
    a1class.classname()
    function a1class:classname()
        return "a1class"
    end
    print (a1class.classname()=="a1class")-- check overwrite
    print (a1class.ctor()) --check  Inheritance
    --print (a1class.super:classname())
    
    ---------------------------------------------------------------------------------------

    第二版:适用方法替代表table

    好处:需要的时候才去遍历基类查找,而非实时new的时候就复制。
    涉及到一个知识__index接收了哪些参数,
    t1.__index(t1,"function_name")
    所以:function __index(tablename,keyname)
    ------------------------------------------------------
    --V2
    ------------------------------------------------------
    baseclass={}
    baseclass.level=0
    baseclass.__index=baseclass
    
    function baseclass:new (o)
          o = o or {}   -- create object if user does not provide one
          o.super=self --  keep base class
          setmetatable(o,
            {__index=function(tablename,keyname)
                -- two way to do it
                return self[keyname] -- or     return o.super[keyname]
    
    
            end
            }
          )
          o.__index=o
          --self.__index = self
          return o
    end
    
    function baseclass:classname()
    return  "baseclass"
    end
    
    function baseclass:ctor()
        return "baseclassctor"
    end
    
    ------------------------------------------------------
    a1class=baseclass:new()
    a1class.classname()
    function a1class:classname()
        return "a1class"
    end
    
    --[[
    function a1class:new (o)
          o = o or {}   -- create object if user does not provide one
          o.super=self --  keep base class
          setmetatable(o,
            {__index=function(tablename,keyname)
                return self[keyname]
    
            end
            }
          )
          o.__index=o
          --self.__index = self
          return o
    end
    --]]
    ---
    
    
    
    print (a1class:classname()=="a1class")-- check overwrite
    print (a1class.level==0)-- check base class 's property
    print (a1class:ctor()=="baseclassctor") --check  Inheritance
    print ("-----------b-----------")
    
    b1Class=a1class:new()
    print (b1Class:ctor()=="baseclassctor")
    print (b1Class:classname()==a1class:classname())--check
    ------------------------------------------------------
     
     
     

    第三版:若子类需要则传递保存下来

    1.保存基类方法到派生类
    2.增加tostring(table)来验证调用的路径
    ------------------------------------------------------
    --V3
    ------------------------------------------------------
    baseclass={}
    baseclass.level=0
    baseclass.__index=baseclass
    
    function baseclass:new (o)
          o = o or {}   -- create object if user does not provide one
          o.super=self --  keep base class
          setmetatable(o,
            {__index=function(tablename,keyname)
                -- two way to do it
                print ("invoke func "..keyname..
                " from "..tostring(tablename).." now is "..tostring(self) )
                 func= self[keyname]
                 if  func then
                    o[keyname]=func
                    --print ("keep it "..keyname.." in "..tostring(self))
                 end
    
    
                return func -- or     return o.super[keyname]
    
    
            end
            }
          )
          o.__index=o
          --self.__index = self
          return o
    end
    
    function baseclass:classname()
    return  "baseclass"
    end
    
    function baseclass:ctor()
        return "baseclassctor"
    end
    
    ------------------------------------------------------
    
    
    a1class=baseclass:new()
    a1class.classname()
    function a1class:classname()
        return "a1class"
    end
    
    
    
    
    print (a1class:classname()=="a1class")-- check overwrite
    print (a1class.level==0)-- check base class 's property
    --print (a1class:ctor()=="baseclassctor") --check  Inheritance
    
    
    b1Class=a1class:new()
    function b1Class:classname()
        return "b1Class"
    end
    
    
    --print (b1Class:ctor()=="baseclassctor")
    print (b1Class:classname()~=a1class:classname())--check
    print (b1Class.level==0)-- check base class 's property
    
    print ("--------check drived class search")
    print (b1Class:ctor())-- check base class 's property
    print (b1Class:ctor())-- check base class 's property
    ------------------------------------------------------
    
    print ("baseclass is "..tostring(baseclass))
    print ("a1class is "..tostring(a1class))
    print ("b1Class is "..tostring(b1Class))
     

    第四版:替代new的方式直接一个函数生成类

    drivedclass==class(baseclass)
    1.直接替代call方法
    2.function 方式
     
     
    第四版:替代new的方式直接一个函数生成类
    drivedclass==class(baseclass)
    1.直接替代call方法
    2.function 方式
    
    ------------------------------------------------------
    --V4 
    ------------------------------------------------------
    function class (baseclass)
    
        local o =   {}
        o.super=baseclass --  keep base class
        setmetatable(o,
            {__index=function(tablename,keyname)
    
            --    print ("invoke func "..keyname..
            --    " from "..tostring(tablename).." now is "..tostring(baseclass) )
    
                 func= baseclass[keyname]
                 if  func then
                    o[keyname]=func
                    --print ("keep it "..keyname.." in "..tostring(self))
                 end
    
    
                return func -- or     return o.super[keyname]
    
    
            end
            }
          )
    
          return o
    end
    
    
    
    ------------------------------------------------------
    baseclass=class()
    baseclass.level=0
    function baseclass:classname()
    return  "baseclass"
    end
    
    function baseclass:ctor()
        return "baseclassctor"
    end
    
    
    a1class=class(baseclass)
    
    function a1class:classname()
        return "a1class"
    end
    
    
    
    
    print (a1class:classname()=="a1class")-- check overwrite
    print (a1class.level==0)-- check base class 's property
    print (a1class:ctor())-- check base class 's property
    --print (a1class:ctor()=="baseclassctor") --check  Inheritance
    
    
    
    b1Class=class(a1class)
    --function b1Class:classname()     return "b1Class" end
    print (b1Class:classname())-- y
    
    ------------------------------------------------------end

    第五版 尝试跨越中间,从基类复制到最终的派生类

    1.明白自己处于初次调用(?)和找到该方法的基类(func not nil可以知道),跨代复制?每次进入基类的时候,存入一个全局表?
    比如设定一个栈;每次进入基类查找的时候就压,直到最后退出的时候才真正给方法并保存。或者计数也行。已计数完成
    2.将找到的方法存储到一个跨所有代的。
    上面2种方法都需要在class外面闭包一个变量?
     
    ------------------------------------------------------
    --V5
    ------------------------------------------------------
     --o =   {}
     local indexlevel=0
    -----------------------------
    function class (baseclass)
    
        local o =   {}
        o.indexlevel=0
        o.super=baseclass --  keep base class
    
        setmetatable(o,
            {__index=function(tablename,keyname)
    
                print ("invoke func "..keyname..
            " from "..tostring(tablename).." now is "..tostring(baseclass) )
    
                print (" enter    indexlevel: "..indexlevel)
                indexlevel=indexlevel+1
    
                 func= baseclass[keyname]
    
    
    
                indexlevel= indexlevel-1
                print (" leave    indexlevel: "..indexlevel)
                if indexlevel==0 then
                    if  func then
                        o[keyname]=func
                    print ("keep it "..keyname.." in "..tostring(baseclass))
                    end
                end
                return func
    
            end
            }
          )
          ---
        o.tablefunctions={}
    
          return o
    end
    
    
    
    ------------------------------------------------------
    baseclass=class()
    baseclass.level=0
    function baseclass:classname()
    return  "baseclass"
    end
    
    function baseclass:ctor()
        return "baseclassctor"
    end
    
    
    a1class=class(baseclass)
    
    function a1class:classname()
        return "a1class"
    end
    
    b1Class=class(a1class)
    
     
    print ("--------check drived class search")
    print (b1Class:ctor())-- check base class 's property
    print (b1Class:ctor())-- check base class 's property
    
    ------------------------------------------------------
    print ("-------------------------------")
    print ("baseclass is "..tostring(baseclass))
    print ("a1class is "..tostring(a1class))
    print ("b1Class is "..tostring(b1Class))

    第六版 学习云风 1:·自定义一个函数容器

    1.保存class属性进全局table
    2.给每个类一个方法容器(表),索引父类的时候直接索引该表。
    4.表赋值操作实际是做了什么操作?~~~
    setmetatable无法正常调用 __newindex,当设定了o的_index的时候
    对同一个对象设置 setmeattable的 index 和newindex时候,newindex会失效
    因为方法覆盖了。 
    5.使用新的class[xx]容器来存储新到的方法,索引本类中和父类中的方法
     
    ------------------------------------------------------
    --V6
    ------------------------------------------------------
     
    
    -------------------------------
     --o =   {}
    -- local indexlevel=0
     local _class={} -- store global var
    -----------------------------
    function class (baseclass)
        local o =   {}
        o.super=baseclass --  store base class
        _class[o]={}
    
        --存储新到的方法
        local storeNewFunc=function(tablename,key,value)
            print ("set func "..key.." in "..tostring(tablename).." v is "..tostring(value) )
            _class[o][key]=value--store new func into  o
        end
    
        -- if base exist then add func lookup
        local searchFunc=function(t,key)
            local func=_class[t][key]
    
            if not func and baseclass then
                print (" search  baseclass "..key)
                func=baseclass[key]
                if func then
                    o[key]=value
                end
            end
    
            if func then
                    print (" func "..key.."   found ")
    
            else
                    print (" func "..key.." nof found ")
            end
    
            return func
    
        end
    
        setmetatable(o,{__index=searchFunc,__newindex=storeNewFunc })
    
    
        return o
    end
    
    
    
    ------------------------------------------------------
    
    baseclass=class()
    print ("-------------------------------")
    function baseclass:classname()
        return  "baseclass"
    end
    print ("-------------------------------")
    
    --print ("classname= "..baseclass:classname())-- check overwrite
    print ("-------------------------------")
    --print ("classname= "..baseclass:classname())-- check overwrite
     
    
    
    function baseclass:ctor()
        return "baseclass_ctor"
    end
    
    
    a1class=class(baseclass)
    
    function a1class:classname()
        return "a1class"
    end
    
    print ("---test class----------------------------")
    print (a1class:classname()=="a1class")-- check overwrite
    print (a1class:ctor()=="baseclass_ctor")-- check overwrite
    print ("---test class 1----------------------------")
    b1Class=class(a1class)
    print ("---test class 2----------------------------")
    
    print (b1Class:ctor())
    print ("---test class 3----------------------------")
    print (b1Class:ctor())
     
    
    ------------------------------------------------------
    print ("-------------------------------")
    print ("baseclass is "..tostring(baseclass))
    print ("a1class is "..tostring(a1class))
    print ("b1Class is "..tostring(b1Class))

    第七版 学习云风2:分离classtype和object

     
     云风分离class和object的方法
     
     
     local _class={}
    -----------------------------
    function class (baseclass)
        local o =   {}
        o.super=baseclass --  store base class ,not nessary
        _class[o]={}
        o.new = function (...)
            local instance={}--instance
    
    
            setmetatable(instance,{__index=o,__newindex=o})
            --setmetatable(instance,{__index=searchFunc,__newindex=storeNewFunc })
            return instance
    
        end
    
        --存储新到的方法
        local storeNewFunc=function(tablename,key,value)
            print ("set func "..key.." in "..tostring(tablename).." v is "..tostring(value) )
            _class[o][key]=value--store new func into  o
        end
    
        --方法查找 if base exist then add func lookup
        local searchFunc=function(t,key)
            local func=_class[t][key]
    
            if not func and baseclass then
                print (" search  baseclass "..key)
                func=baseclass[key]
                if func then
                    o[key]=func
                end
            end
    
            if func then
                    print (" func "..key.."   found ")
    
            else
                    print (" func "..key.." nof found ")
            end
    
            return func
    
        end
    
        setmetatable(o,{__index=searchFunc,__newindex=storeNewFunc })
    
    
        return o
    end
    
    
    
    ------------------------------------------------------
    
    baseclass=class()
    print ("-------------------------------")
    function baseclass:classname()
        return  "baseclass"
    end
    print ("-------------------------------")
    
    --print ("classname= "..baseclass:classname())-- check overwrite
    print ("-------------------------------")
    --print ("classname= "..baseclass:classname())-- check overwrite
    --dump(_class)
    
    
    function baseclass:ctor()
        return "baseclass_ctor"
    end
    
    
    a1class=class(baseclass)
    
    function a1class:classname()
        return "a1class"
    end
    
    
    b1Class=class(a1class)
    bb1=b1Class.new()
    print ("---test class 5----------------------------")
    print (bb1:ctor())
    print (bb1:ctor())
    print (bb1:ctor())
     
     
     

     4.个人小结

     
    1.通过打印来调试,实在不行就debug吧。。
    2.少点copy,适当手打,会免除一些基本错误。
    3.以为懂的,不一定真的懂,有点模糊的话,看懂后,按自己的思路实现(手打)试试看。
    4.代码格式蛮重要的。。。清晰的格式更容易审计代码
     

     5.参考资料

    1. 云风.在 Lua 中实现面向对象.http://blog.codingnow.com/2006/06/oo_lua.html 已阅
    2.[作者]16 – Object-Oriented Programming.http://www.lua.org/pil/16.html 已阅
    【存储父类方法到本地能够减少调用回溯的开销】包含系列方案
    3. Lua下通过元表模拟OOP编程,继承多态.http://blog.csdn.net/yue7603835/article/details/41814203 (解释还行,)
    4.http://www.360doc.com/content/14/0113/21/9200790_345058007.shtml(将self.__index=self放到了外面)
    4.基于closure的lua面向对象编程.http://blog.csdn.net/hopingwhite/article/details/19980473
     
    http://lua-users.org/wiki/ObjectOrientedProgramming
     
    http://lua-users.org/wiki/InheritanceTutorial
    提供clone和is-a的方法
    http://lua-users.org/wiki/ObjectOrientationClosureApproach
    编码实现了两种方案并且给出结论:闭包class性能更好,适用于大的对象,table只适合小的。
  • 相关阅读:
    iOS 苹果开发证书失效的解决方案(Failed to locate or generate matching signing assets)
    iOS NSArray数组过滤
    App Store2016年最新审核规则
    iOS 根据字符串数目,自定义Label等控件的高度
    iOS 证书Bug The identity used to sign the executable is no longer valid 解决方案
    Entity FrameWork 增删查改的本质
    EF容器---代理类对象
    Entity FrameWork 延迟加载本质(二)
    Entity FrameWork 延迟加载的本质(一)
    Entity FrameWork 增删查改
  • 原文地址:https://www.cnblogs.com/facingwaller/p/LUA_ObjectOrientedProgramming.html
Copyright © 2020-2023  润新知