Lua学习笔记(4)面向对象实现
百度搜索一下,给出出的解决方案和学习帖子很多,可是我还是有很多的问题!
-
什么是面向对象?
-
lua中怎么实现面向对象?
-
什么样的实现既简单又能完成我的功能?
-
一定要按照c++的方式实现类的继承吗?
在学习lua面向对象的过程中我比较喜欢下面两种实现方式:
简单粗暴的实现
参考[1]:参考同事的方法,如果借鉴、转载请注明
在lua中,我们知道table是万能的一个类型,当我们用table实现一个基类和子类的时候,他们都是确确实实存在的一个个table,都是有地址的。不会说像c++一样,类定义是类定义,只有new出来才是真正可以使用的,而lua却不是这样。所以,最简单的一种方法就是,每次继承基类的时候,直接copy基类的所有内容,函数除外,其他的成员都重新复制一遍,如果是table的话重新构建一个,并且把内容拷贝过来。代码如下:
参考代码:
--lua面向对象:简单粗暴的实现function copytable(tbArg)
local tbCollsion = {}
--local的作用域问题local copy
copy = function (obj)
if type(obj) ~= "table" thenreturn obj;
end--检查是否有嵌套循环的tableif tbCollsion[obj] thenreturn tbCollsion[obj];
endlocal tbNew = {}
tbCollsion[obj] = tbNew;
--递归复制for k, v in pairs(obj) do
tbNew[k] = copy(v);
end--复制完之后,元表关系也要保留下来return setmetatable(tbNew, getmetatable(obj))
endreturn copy(tbArg);
endfunction inherit(tbBase, tbClass)
–复制基类local tbNew = copytable(tbBase)
local tm = {}
tm.__index = tbClass;
setmetatable(tbNew, tm)
--修改tbBase为tbClass中的成员或者新增加tbClass中的成员if tbClass thenfor k, v in pairs(tbClass) do
tbNew[k] = v
endendreturn tbNew;
end–使用local tbObject = {}
local tbFruit = inherit(tbObject)
local tbApple = inherit(tbFruit)
local tbBanana = inherit(tbFruit)
local tbBanana1 = inherit(tbFruit)
local tbBanana2 = inherit(tbFruit, tbBanana1)
优点:
-
好理解
-
好用,不会出现共用一个table引用,导致其中一个修改影响了另外一个
-
共享函数引用
缺点:
-
真正意义上的面向对象,继承等概念不清晰
-
一个子类new多个对象的概念是没有的,和继承已经混在了一起,所以如果要实现new多个对象的话,有代码冗余
概念意义上的实现
参考[2]:云风的blog,如果借鉴、转载请注明
这种从概念上实现面向对象的方法做到以下几点:
-
有类定义和对象的概念,类定义通过new来创建对象,并且同时调用自己的构造函数
-
子类可以访问基类的成员函数
-
类定义不能够调用函数(除了new之外),只有对象才能调用函数
-
构造函数调用有和c++一样的层级关系,先调用父类的构造函数,再调用子类的构造函
参考代码:
--lua面向对象:概念意义上的实现local _class={}
function class(super)
local class_type={}
–注意:因为重载了__newindex函数, 所以ctor不要定义为nil
class_type.ctor=false
class_type.super=super
class_type.new=function(…)
local obj={}
–下面的块只做了一件事:依次从父类到当前子类调用构造函数ctordolocal create
create = function(c,…)
if c.super then
create(c.super,…)
endif c.ctor then
c.ctor(obj,…)
endend
create(class_type,...)
endsetmetatable(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
})
--只有定义类修改了__newindex--vbtl只属于定义类--new出来的对象共享所有定义类的引用,但独享自己新增加的成员变量if super thensetmetatable(vtbl,{__index=
function(t,k)
local ret=_class[super][k]
vtbl[k]=ret
return ret
end
})
endreturn class_type
end
说明几点:
- 只有定义类修改了__newindex
- vbtl只属于定义类
- new出来的对象共享所有定义类的引用,但独享自己新增加的成员变量
优点:
-
概念上更加清晰,熟悉c++面向对象的很容易了解这个继承的关系
-
写法上感觉很牛逼,做到了定义不能调用函数这一点
-
共享函数引用
缺点:
-
概念上清晰的成本是要更多的时间去理解
-
虽然做到了c++类定义和对象上的概念区别,但是还是有多东西没有实现
-
对象也可以定义自己的函数,这一点就直接打破了区分定义和对象的本源,但是价值还是有的
-
所有new出来对象共享类定义的引用对象,包括不需要复用的函数和table。由此多个对象共享一个定义的table很是个问题!
针对最后一条,可以通过实现定义的init函数,在init函数给不同的对象初始化不同的数据,即使是table!
总结
-
面向对象
-
lua中的实现最主要就是使用talbe的元表和元方法
-
lua本身是用c实现的,可以做到很复杂的事情,但是做到满足自己的需求即可,没有必要搞得很复杂;如果非要苛求的话,往往会适得其反,不仅复杂难理解,性能上也会有影响
参考
[1]同事
[2]云风blog