笔者学习了当前(文末各文献)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=
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==)-- 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=
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==)-- 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==)-- 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)
.直接替代call方法
.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=
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==)-- 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=
-----------------------------
function class (baseclass) local o = {}
o.indexlevel=
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+ func= baseclass[keyname] indexlevel= indexlevel-
print (" leave indexlevel: "..indexlevel)
if indexlevel== 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=
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只适合小的。

lua下的简单OO实现的更多相关文章

  1. lua Getter&Setter简单实现

    lua是一门简单的语言,不带类和属性封装,但可以使用lua强大的元表模拟实现: class.lua local type = type local rawset = rawset local setm ...

  2. ios下最简单的正则,RegexKitLite

    ios下最简单的正则,RegexKitLite 1.去RegexKitLite下载类库,解压出来会有一个例子包及2个文件,其实用到的就这2个文件,添加到工程中.备用地址:http://www.coco ...

  3. cocos2d-x lua与c++简单交互

    cocos2d-x lua与c++简单交互 version: cocos2d-x 3.6 本文讲述lua与c++的一些简单交互: lua通过消息方式调用c++无参接口 c++调用lua带参接口 1.通 ...

  4. Linux下一个简单的日志系统的设计及其C代码实现

    1.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件.在日志文件中存放程序流程中的一些重要信息, 包括:变量名称及其值.消息结构定义.函数返回 ...

  5. VIM - visual selection 模式下的简单操作

    1. 概述 vim 的 visual selection 模式下的简单操作 2. visual selection 模式 概述 可视化选择 可视化选择 vim 的一种专门用来选择的模式 可以提供相对于 ...

  6. [Android] Android MVP 架构下 最简单的 代码实现

    Android  MVP 架构下  最简单的 代码实现 首先看图: 上图是MVP,下图是MVC MVP和MVC的区别,在于以前的View层不仅要和model层交互,还要和controller层交互.而 ...

  7. Windows环境下ELK简单搭建记录

    前言 ELK已经是一套成熟的日志解决方案,虽然出现了好久,今日才终于研究了一下,不过是在windows平台上安装的. 搭建步骤 下载软件 安装软件 修改配置文件 启动软件 集成测试 下载软件 首先从官 ...

  8. (转)live555在Linux下最简单地实现实时流媒体点播

    通过Live555交叉编译后运行发现,上面实现的流媒体实时通过文件服务器的文件点播,没有相关的流媒体实现方式, 但在Linux下,可以通过某些技巧实现Live555服务器实时流媒体服务器,并且是傻瓜式 ...

  9. nginx Win下实现简单的负载均衡(2)站点共享Session

    快速目录: 一.nginx Win下实现简单的负载均衡(1)nginx搭建部署 二.nginx Win下实现简单的负载均衡(2)站点共享Session 三.nginx Win下实现简单的负载均衡(3) ...

随机推荐

  1. MEF Parts Sample

    namespace Microshaoft.MEF.Contracts { using System; public delegate void ExceptionEventHandler<TS ...

  2. jqGrid配置属性说明

    Property Type Description Default1) ajaxGridOptions object This option allows to set global ajax set ...

  3. 激活Windows 8.1 RTM原来如此简单

    日前,Windows 8.1 RTM各种版本已经在坊间泄露开来,许多迫不及待的用户也开始跃跃欲试,但可能有人会疑惑,Windows 8.1RTM该如何激活?其实,它远比你想象的要简单. 实际上,Win ...

  4. PropertyMetadata和UIPropertyMetadata的一点区别

    使用UIPropertyMetadata写一个Brush的依赖属性. System.Windows.Application.Current.Dispatcher.BeginInvoke(new Act ...

  5. jQuery插件(cookie存值)

    使用cookie插件后,可以很方便地通过cookie对象保存.读取.删除用户的信息,还能通过cookie插件保存用户的浏览记录,它的调用格式为: 保存:$.cookie(key,value):读取:$ ...

  6. jq switch case

    switch (cnt) {                    case ("string1"):                        ...             ...

  7. Leetcode First Missing Positive

    Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2,0]  ...

  8. PHP+Mysql+easyui点击左侧tree菜单对应表名右侧动态生成datagrid加载表单数据(二)

    关于tree菜单生成,参考我的另一篇博文地址tree 菜单 实现功能:点击左侧tree菜单中的table,右侧通过datagrid加载出该表对用的所有数据 难点:获取该表的所有列名,动态生成datag ...

  9. cetnos 7 ntp服务的安装与配置

    首先需要搭建yum本地仓库 http://www.cnblogs.com/jw35/p/5967677.html   #搭建yum仓库方法 yum install ntp -y        #安装n ...

  10. dedecms二级导航标签调用使用的方法

    <ul class="nav nav-pills blue"> <!--一级栏目下面有二级栏目的 --> {dede:channelartlist type ...