Lua函数闭包实现面向对象
19 March 2015
定义一个方法,函数闭包实现一个类的概念:
function People(name)
local self = {}
--初始化方法,私有的
local function init()
self.name = name
end
self.sayHi = function ()
print("Hello "..self.name)
end
--调用初始化
init()
return self
end
实例化一个对象:
local p = People("Sure")
p:sayHi()
函数闭包的形式实现类继承:
function Man(name)
local self = People(name)
-- local function init()
--
-- end
self.sayHello = function ()
print("Hi "..self.name)
end
return self
end
实例化一个子类对象:
local m = Man("Sure")
--m:sayHello()
m:sayHi()
理解OO的本质
这里可以理解一下OO的本质:
Account = {balance = 0}
function Account.withdraw (v)
Account.balance = Account.balance - v
end
即等价于:
Account = {
balance=0,
withdraw = function (v)
Account.balance = Account.balance - v
end
}
这个类中的withdraw是不符合OO的。 因为
a = Account; Account = nil a.withdraw(100.00) – ERROR!
就是说实例名称必须是固定的Account,这是很糟糕的。而要消除这种问题,可以这样:
Account = {
balance=0,
withdraw = function (self, v)
self.balance = self.balance - v
end
}
也就是在调用的时候把实例名称带进去,也就是:
a1 = Account; Account = nil a1.withdraw(a1, 100.00) – OK
那么这才是OO的,因为这个方法可以用于这个类的每个实例上!
继续来说,这里的self在其他OO语言中是隐藏默认实现的,而lua因为本质上不是OO语言才需要这样写。不过lua提供一种冒号写法来简写:
function Account:withdraw (v)
self.balance = self.balance - v
end
同样的,调用也可以用冒号简写: a:withdraw(100.00)
所以说来总结一下: 1. 方法如果写在表内,就不需Class.前缀;如果在表外定义,就需要。 2. 声明时,Class.func(self,v)等价于Class:func(v) 3. 调用时,a.func(a,100)等价于a:func(100) 冒号提供的只是语法层面的便利。
比如这个例子,上面说的三点都涵盖了:
Account = {
balance=0,
withdraw = function (self, v)
self.balance = self.balance - v
end
}
function Account:deposit (v)
self.balance = self.balance + v
end
Account.deposit(Account, 200.00)
Account:withdraw(100.00)
实例
lua不是OO,new是用表作为metatable,就是说: a = A:new(),就是说用A的格式来创建a,那么在术语上A就可以称为类,a就可以称为实例。
new
quick的function.lua中new的实现,是调用了ctor。从中可以看出,ctor用冒号,调用new时用点号。
function cls.new(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k,v in pairs(cls) do instance[k] = v end
instance.class = cls
instance:ctor(...)
return instance
end
-EOF-