类和对象:
account.lua
module(...,package.seeall) Account={balance=0} Account.new=function(self,o) local o=o or {} setmetatable(o,self) self.__index=self return o end Account.getBalance=function(self) return self.balance end Account.setBalance=function(self,money) self.balance=money end Account.withdraw=function(self,money) if money<0 then error("<Account.deposit> money must > 0") else if money > self.balance then error("<Account.deposit> no enough balance") end self.balance=self.balance-money end end Account.deposit=function(self,money) if money <0 then error("<Account.deposit> money must > 0") end self.balance=self.balance+money end Account.__tostring=function(self) str=os.date("%y/%m/%d %H:%M:%S",os.time()) str=string.format("%s\nBalance:%s",str,self.balance) return str end
注:
Lua检测到没有的字段时,但在其元表中有一个__index字段,那么Lua会调用这个__index元方法,并返回结果,__index元方法可以使函数或者是table,当元方法是一个函数时,Lua以table和不存在的key做为参数来调用该函数,当元方法是一个table时,Lua重新访问这个table。
上述代码,当调用Account:new 时,self等于Account,因此可以直接使用Account来代替self,当引入类的继承时,使用self更加准确。
继承:
specialAccount.lua
module(...,package.seeall) SpecialAccount=MAccount.Account:new({limit=1000.0}) SpecialAccount.getLimit=function(self) return self.limit end SpecialAccount.withdraw=function(self,money) if money <0 then str="<SpecialAccount.withdraw> money must > 0" Logger:error(str) error(str) end if money > self:getLimit() then Logger:warn("<SpecialAccount.with> withdraw > limit") return end self.balance=self.balance-money end SpecialAccount.__tostring=function(self) str=string.format("%s\nLimit:%d",MAccount.Account.__tostring(self),self.limit) return str end
说明:
SpecialAccount继承了Account的所有函数和变量,在执行SpecialAccount的new函数,它的self参数表示为SpecialAccount,因此执行以下语句:
s表示的元表为SpecialAccount,而SpecialAccount中的__index值也是SpecialAccount,s继承自SpecialAccount,而SpecialAccount又继承自Account,Lua在s中找不到deposit字段时,会查找SpecialAccount,如果仍找不到deposit字段,就会查找Account,最终会在那里找到deposit字段。
SpecialAccount重新定义了基类继承的方法,如SpecialAccount中的withdraw函数,当调用s:withdraw(200)时,Lua就不会再Account中查找了,因为Lua会在SpecialAccount中找到withdraw方法。
补充说明:
Lua中对象有一个特殊现象,无需为指定一种新行为而创建一个新类,如果只有一个对象需要这种特殊的行为,那么可以直接在该对象中实现这个行为,例如,账户s表示一个特殊的客户,这个客户的透支额度总是余额的10%。那么可以这么修改这个对象:
在这段代码后,调用s:withdraw(200)还是会执行SpecialAccount中的withdraw函数,但是withdraw调用的self:getLimit则是上面的定义。
完整代码:
模块结构:
init.lua
MAccount=require("class.account") MSpecialAccount=require("class.specialAccount") local LoggerConsole=require("logging.console") Logger=LoggerConsole()
main.lua
local path="C:\\Users\\Administrator\\Desktop 2\\Thinking\\Lua\\" package.path=string.format("%s;%s?.lua;%s?/init.lua",package.path,path,path) require("class") local function main() local account=MAccount.Account:new() account:deposit(500) account:withdraw(125) print(account) account=MSpecialAccount.SpecialAccount:new() print(account:getLimit()) account:deposit(300) account:withdraw(1200) print(account) end main()
说明:
上述修改了package.path 的路径,具体原因参考 本博客“【Lua】模块和包”文章