Lua的面向对象程序设计
Account={balance=0} function Account.withdraw(self,v) self.balance=self.balance-v end a={balance=0,withdraw=Account.withdraw} a.withdraw(a,260) --面向对象语言常使用self参数,lua提供了通过使用冒号操作符来隐藏self参数的声明 function Account:withdraw(v) self.balance=self.balance-v end a:withdraw(100.0) --冒号的效果相当于在函数定义和函数调用的时候,增加一个额外的隐藏参数 --我们可以使用dot语法定义函数而用冒号语法调用函数,反之亦然,只要我们正确的处理好额外的参数. --dot语法定义时要加上self参数,调用时要传入相应的对象,冒号语法不用self参数,调用时也不需要相应的参数对象
Lua中对象没有类,每个对象有一个原型prototype,当调用不属于对象的某些操作时,会最先会到prototype中查找这些操作。
Account={balance=0} function Account:withdraw(v) self.balance=self.balance-v end function Account:deposit(v) self.balance=self.balance+v end function Account:new(o)--返回一个子对象 o=o or {} setmetatable(o,self)--Account成为o的原型 self.__index=self return o end a=Account:new{balance=0} print(a.balance)--输出0 a:deposit(100.00) print(a.balance)--输出100
Account={balance=0} function Account:withdraw(v) if v>self.balance then error"insufficient funds" end self.balance=self.balance-v end function Account:deposit(v) self.balance=self.balance+v end function Account:new(o) o=o or {} setmetatable(o,self)--Account成为o的原型 self.__index=self return o end SpecialAccount=Account:new() function SpecialAccount:getLimit() return self.limit or 0 end --子类可以重定义从父类中继承来的方法 function SpecialAccount:withdraw(v) if v-self.balance>=self:getLimit() then error"insufficeint funds" end self.balance=self.balance-v end s=SpecialAccount:new{limit=1000.00} function s:getLimit() return self.balance*0.1 end s:withdraw(200.0)--该调用将运行SpecialAccount的withdraw方法,但是当 --方法调用self:getLimit时,最后的定义被触发.
多重继承:将函数用作__index。当一个表的metatable存在一个__index函数时,如果lua调用一个原始表中不存在的函数,Lua将调用这个__index指定的函数,这样可以用__index实现在多个父类中查找子类不存在的域。
--原型,相当于父类 Account={money=0} function Account:save(v) self.money=self.money+v end function Account:spend(v) self.money=self.money-v if self.money<0 then error"there is not enough money" end end function Account:new(o) o=o or {} setmetatable(o,self) self.__index=self--首先在o的原型中查找,然后在原型的__index中查找 return o end --k是缺少的域,plist是table,其元素也是table 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={} --__index是函数时,Lua将table和其缺少的域作为参数调用这个函数 setmetatable(c,{__index=function(t,k) print(t,k) return search(k,arg) end}) c.__index=c function c:new(o) o=o or {} setmetatable(o,c) return o end return c end Named={} function Named:getname() return self.name end function Named:setname(s) self.name=s end NamedAccount=createClass(Account,Named) account=NamedAccount:new{name="paul"} print(NamedAccount) print(account:getname()) --[[ table: 0039C988 table: 0039C988 getname paul ]]
私有性
function newAccount(initialBalance) --存储在self表中的部分都是私有的 local self={balance=initialBalance} local withdraw=function(v) self.balance=self.balance-v end local deposit=function(v) self.balance=self.balance+v end local getBalance=function() return self.balance end return { withdraw=withdraw, deposit=deposit, getBalance=getBalance } end instance=newAccount(100) print(instance.getBalance()) instance.withdraw(40) print(instance.getBalance())
single-method的对象实现方法:当对象只有一个单一的方法时,可以将这个单一的方法作为对象返回
function newObject(value) return function(action,v) if action=="get" then return value elseif action=="set" then value=v else error("invalid action") end end end --每一个对象是一个单独的闭包,代价比表小得多,这种方式没有继承但有私有性:访问 --对象状态的唯一状态是通过它的内部方法 d=newObject(0)--d这个对象是newObject返回的单一方法 print(d("get"))--0 d("set",10) print(d("get"))--10