local Account = {balance = 0}
function Account.withdraw(v)
Account.balance = Account.balance - v
end
--调用方法如下:
Account.withdraw(100.00)
local a = Account
Account = nil
a.withdraw(100.00) -- ERROR!--这种行为违背了前面的对象应该有独立的生命周期的原则。
一个灵活的方法是:定义方法的时候带上一个额外的参数,来表示方法作用的对象。这个参数经常为self或者this:
function Account.withdraw(self, v)
self.balance = self.balance - v
end
self参数的使用是很多面向对象语言的要点。大多数OO语言将这种机制隐藏起来,就行C++中的this关键字一样,这样程序员不必声明这个参数(虽然仍然可以在方法内使用这个参数)。Lua也提供了通过使用冒号操作符来隐藏这个参数的声明。我们可以重写上面的代码:
function Account:deposit(v)
self.balance = self.balance + v
end
--调用方法如下:
a:withdraw(100.00)
冒号的效果相当于在函数定义和函数调用的时候,增加一个额外的隐藏参数。这种方式只是提供了一种方便的语法,实际上并没有什么新的内容。
用lua进行面向对象的编程,声明方法和调用方法统一用冒号,对于属性的调用全部用点号。(链接)
local Account = {balance = 0}
function Account:new(o)
o = o or {}
setmetatable(o,{__index = self})
return o
end
function Account:deposit (v)
self.balance = self.balance + v
print(self.balance)
end
a = Account:new{balance = 0}
a:deposit(100.00) --输出 100
local Account = {balance = 0}
function Account:new(o)
o = o or {}
setmetatable(o,{__index = self})
return o
end
function Account:deposit(v)
self.balance = self.balance + v
print("Account:deposit",self.balance)
end
function Account:withdraw(v)
if v > self.balance then
error"insufficient funds"
end
self.balance = self.balance - v
print("Account:withdraw",self.balance)
end
local SpecialAccount = Account:new()
function SpecialAccount:withdraw(v)
if v - self.balance >= self:getLimit() then
error"insufficient funds"
end
self.balance = self.balance - v
print("SpecialAccount:withdraw",self.balance)
end
function SpecialAccount:getLimit()
print("SpecialAccount:getLimit",self.limit or 0)
return self.limit or 0
end
local s = SpecialAccount:new{limit=1000.00}
function s:getLimit ()
print("s:getLimit",self.balance * 0.10)
return self.balance * 0.10
end
s:deposit(100.00)
s:withdraw(10.00)
--输出
--Account:deposit 100
--s:getLimit 10
--SpecialAccount:withdraw 90
s的表结构
多重继承意味着一个类拥有多个父类,所以,我们不能用创建一个类的方法去创建子类。取而代之的是,我们定义一个特殊的函数createClass来完成这个功能,将被创建的新类的父类作为这个函数的参数。这个函数创建一个表来表示新类,并且将它的metatable设定为一个可以实现多继承的__index metamethod。尽管是多重继承,每一个实例依然属于一个在其中能找得到它需要的方法的单独的类。所以,这种类和父类之间的关系与传统的类与实例的关系是有区别的。特别是,一个类不能同时是其实例的metatable又是自己的metatable。
local function search(k, plist)
for i=1,table.getn(plist) do
local v = plist[i][k]
if v then return v end
end
end
function createClass(...)
local c = {} -- new class
setmetatable(c,{__index = function(t, k) return search(k,arg) end})
function c:new (o)
o = o or {}
setmetatable(o,{__index = c})
return o
end
return c
end
local Named = {}
function Named:getname()
return self.name
end
function Named:setname(n)
self.name = n
end
local NamedAccount = createClass(Account, Named)
local ssaccount = NamedAccount:new{name = "Paul"}
print(ssaccount:getname()) --> Paul
其他相关内容可参看,《Lua基础(二)——表》,《Lua表相关元方法》,《Lua进阶(一)——函数闭包、元表》
参考, 云风的个人空间 : Lua 中实现面向对象, Lua 面向对象实现