zoukankan      html  css  js  c++  java
  • 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只适合小的。
  • 相关阅读:
    Response.Redirect 产生的“正在中止线程”错误,不再执行下面语句解决办法
    c#中采用OLEDB方式来读取EXCEL文件和将数据写入EXCEL文件
    https,https的本地测试环境搭建,asp.net结合https的代码实现,http网站转换成https网站之后遇到的问题
    [bzoj2427][HAOI2010]软件安装——强连通分量+树形DP
    [bzoj3931][CQOI2015]网络吞吐量——最短路+网络流
    [bzoj1823][JSOI2010]满汉全席——2-SAT
    [bzoj1486][HNOI2009]最小圈——分数规划+spfa+负环
    [bzoj3532][Sdoi2014]Lis——拆点最小割+字典序+退流
    [bzoj3876][AHOI2014]支线剧情——上下界费用流
    [bzoj2127]happiness——最小割
  • 原文地址:https://www.cnblogs.com/facingwaller/p/LUA_ObjectOrientedProgramming.html
Copyright © 2011-2022 走看看