Lua中的表不仅在某种意义上是一种对象。像对象一样,表也有状态(成员变量);也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。
在Lua中,很容易实现prototypes.更明确的来说,如果我们有两个对象a和b,我们想让b作为a的prototype只需要:setMetatable(a,{__index = b})
在Lua中多重继承的实现的关键在于:将函数用作__index。记住,当一个表的Metatable存在一个__index函数时,如果Lua调用一个原始表中不存在的函数,Lua将调用这个__index指定的函数。这样可以用__index实现在多个父类中查找子类不存在的域。
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 endself参数的使用是很多面向对象语言的要点。大多数OO语言将这种机制隐藏起来,就行C++中的this关键字一样,这样程序员不必声明这个参数(虽然仍然可以在方法内使用这个参数)。Lua也提供了通过使用冒号操作符来隐藏这个参数的声明。我们可以重写上面的代码:
function Account:deposit(v) self.balance = self.balance + v end --调用方法如下: a:withdraw(100.00)
冒号的效果相当于在函数定义和函数调用的时候,增加一个额外的隐藏参数。这种方式只是提供了一种方便的语法,实际上并没有什么新的内容。
用lua进行面向对象的编程,声明方法和调用方法统一用冒号,对于属性的调用全部用点号。(链接)
类
一些面向对象的语言中提供了类的概念,作为创建对象的模板。在这些语言里,对象是类的实例。Lua不存在类的概念,每个对象定义他自己的行为并拥有自己的形状(shape)。然而,依据基于原型(prototype)的语言比如Self和NewtonScript,在Lua中仿效类的概念并不难。在这些语言中,对象没有类。相反,每个对象都有一个prototype(原型),当调用不属于对象的某些操作时,会最先会到prototype中查找这些操作。在这类语言中实现类(class)的机制,我们创建一个对象,作为其它对象的原型即可(原型对象为类,其它对象为类的instance)。类与prototype的工作机制相同,都是定义了特定对象的行为。[设计模式]Prototype原型模式在Lua中,很容易实现prototypes.更明确的来说,如果我们有两个对象a和b,我们想让b作为a的prototype只需要:setMetatable(a,{__index = b})
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 90s的表结构
多重继承
多重继承意味着一个类拥有多个父类,所以,我们不能用创建一个类的方法去创建子类。取而代之的是,我们定义一个特殊的函数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
私有性
用一个table表来保存数据,用另一个表table来保存函数。其他相关内容可参看,《Lua基础(二)——表》,《Lua表相关元方法》,《Lua进阶(一)——函数闭包、元表》
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。