要理解Lua是如何实现面向对象的。首先要熟悉Lua元表的相关知识,可以阅读我上一篇文章《Lua元表 (Metatable)》。其次要熟悉面向对象的一些基本概念:类、对象、继承、封装、多态等。
对象: 可以看作一个是我们用一段数据表示的一个具体的事物,这段数据占据着计算机的一段存储空间,并且有生命周期。 lua中的table就有这一特性。
类: 是对具有属性相同的对象的一种归纳,可以看作一个模板或者原型。然后我们用这个原型去造对象。 这个原型也占据着计算机的一段内存空间,只不过它被创造出来就一直在那呆着,只有一份。因此我们可以用一个一直存在的对象去作为一个原型来代表一个类,lua中require一个lua文件时会只执行这个文件一次,并会记录这个文件。由此我们可以推出:可以用一个文件模拟一个类,而这个文件本质上就是一个table占据着一段内存空间。
继承:用一个原型(类)生成一个对象,这个对象就拥有了原型里面的东西,然后我们将这个对象也作为一个原型(类)使用,那么就有了两个原型(类),后者继承了前者。
封装:就是将一个类的属性以及它的一些操作写在一个文件中。
多态性:一个原型生成了多个原型。新的原型中都对从父原型继承过来的某些操作进行了修改或新增了某些操作,程序执行时产生不同的结果。
以上面向对象的特性,在lua 中我们可以通过table以及设置了元表的table模拟出来。看下面代码实现:
1、我们创建第一个文件tree.lua:一个tree类 并用它生成对象
local tree = {} ---创建 一个table
tree.leafColor = "green" ---- 为这个table添加属性
tree.height = 50
function tree:new(color,height) ---- 构造对象的方法
local instance = {} -----创建一个对象table
setmetatable(instance,{__index = self}) -----设置元表
return instance -----返回对象
end
function tree:grow(year) -----添加一个方法
print("tree:grow")
self.height = self.height+year*0.5
end
return tree
如上代码中设置元表时,将__index键指向当前tree这个table, 所以tree:new()返回的对象可以访问到tree的属性以及grow()方法,执行如下代码:
local tree = require("tree")
local atree = tree:new()
print(atree.leafColor,atree.height)
atree:grow(10)
print("atree.height = ",atree.height)
打印结果:
green 50
tree:grow
atree.height = 55.0
atree拥有了tree的属性和方法。atree 就是tree生成的一个对象。
2、我们创建一个继承tree的类:specialtree
local tree = require('tree')
local specialtree = tree:new() ----用tree创建一个用于做原型的对象
function specialtree:new() ----为specialtree添加构造对象的方法
local instance = {}
setmetatable(instance,{__index = self})
return instance -----返回一个设置了元表__index键指向speciltree的table
end
---重构父类方法
function specialtree:grow (year)
print("specialtree:grow")
self.height = self.height+year*1
end
return specialtree
执行如下代码:
local specialtree = require("specialtree")
local aspecialtree = specialtree:new()
print(aspecialtree.leafColor,aspecialtree.height)
aspecialtree:grow(10)
print("aspecialtree.height = ",aspecialtree.height)
打印结果:
green 50
specialtree:grow
aspecialtree.height = 60
从输出结果可以看出,aspeciltree对象拥有了tree中定义的leafColor和height属性。aspeciltree调用grow方法时,speciltree类中重写了这个方法就不会去tree里面执行了。speicltree成功继承了tree的属性和方法。
另外lua中也是可以模拟多继承的,提供一个构造对象的方法,设置对象的元表时将__index指向一个function,然后在function中去实现在多个类中查找属性与方法。