16.2 继承 |
通常面向对象语言中,继承使得类可以访问其他类的方法,这在Lua中也很容易现实:
假定我们有一个基类Account:
Account = {balance = 0}
function Account:new (o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Account:deposit (v)
self.balance = self.balance + v
end
function Account:withdraw (v)
if v > self.balance then error"insufficient funds" end
self.balance = self.balance - v
end
我们打算从基类派生出一个子类SpecialAccount,这个子类允许客户取款超过它的存款余额限制,我们从一个空类开始,从基类继承所有操作:
SpecialAccount = Account:new()
到现在为止,SpecialAccount仅仅是Account的一个实例。现在奇妙的事情发生了:
s = SpecialAccount:new{limit=1000.00}
SpecialAccount从Account继承了new方法,当new执行的时候,self参数指向SpecialAccount。所以,s的metatable是SpecialAccount,__index 也是SpecialAccount。这样,s继承了SpecialAccount,后者继承了Account。当我们执行:
s:deposit(100.00)
Lua在s中找不到deposit域,他会到SpecialAccount中查找,在SpecialAccount中找不到,会到Account中查找。使得SpecialAccount特殊之处在于,它可以重定义从父类中继承来的方法:
function SpecialAccount:withdraw (v)
if v - self.balance >= self:getLimit() then
error"insufficient funds"
end
self.balance = self.balance - v
end
function SpecialAccount:getLimit ()
return self.limit or 0
end
现在,当我们调用方法s:withdraw(200.00),Lua不会到Account中查找,因为它第一次救在SpecialAccount中发现了新的withdraw方法,由于s.limit等于1000.00(记住我们创建s的时候初始化了这个值)程序执行了取款操作,s的balance变成了负值。
在Lua中面向对象有趣的一个方面是你不需要创建一个新类去指定一个新的行为。如果仅仅一个对象需要特殊的行为,你可以直接在对象中实现,例如,如果账号s表示一些特殊的客户:取款限制是他的存款的10%,你只需要修改这个单独的账号:
function s:getLimit ()
return self.balance * 0.10
end
这样声明之后,调用s:withdraw(200.00)将运行SpecialAccount的withdraw方法,但是当方法调用self:getLimit时,最后的定义被触发。