Lua中的table就是一種對(duì)象,但是如果直接使用仍然會(huì)存在大量的問題,見如下代碼:
在上面的withdraw函數(shù)內(nèi)部依賴了全局變量Account,一旦該變量發(fā)生改變,將會(huì)導(dǎo)致withdraw不再能正常的工作,如:
1. 類:
Lua在語(yǔ)言上并沒有提供面向?qū)ο蟮闹С郑虼讼雽?shí)現(xiàn)該功能,我們只能通過table來模擬,見如下代碼及關(guān)鍵性注釋:
--new可以視為構(gòu)造函數(shù)
function Account:new(o)
o = o or {} --如果參數(shù)中沒有提供table,則創(chuàng)建一個(gè)空的。
--將新對(duì)象實(shí)例的metatable指向Account表(類),這樣就可以將其視為模板了。
setmetatable(o,self)
--在將Account的__index字段指向自己,以便新對(duì)象在訪問Account的函數(shù)和字段時(shí),可被直接重定向。
self.__index = self
--最后返回構(gòu)造后的對(duì)象實(shí)例
return o
end
--deposite被視為Account類的公有成員函數(shù)
function Account:deposit(v)
--這里的self表示對(duì)象實(shí)例本身
self.balance = self.balance + v
end
--下面的代碼創(chuàng)建兩個(gè)Account的對(duì)象實(shí)例
--通過Account的new方法構(gòu)造基于該類的示例對(duì)象。
a = Account:new()
--[[
這里需要具體解釋一下,此時(shí)由于table a中并沒有deposite字段,因此需要重定向到Account,
同時(shí)調(diào)用Account的deposite方法。在Account.deposite方法中,由于self(a對(duì)象)并沒有balance
字段,因此在執(zhí)行self.balance + v時(shí),也需要重定向訪問Account中的balance字段,其缺省值為0。
在得到計(jì)算結(jié)果后,再將該結(jié)果直接賦值給a.balance。此后a對(duì)象就擁有了自己的balance字段和值。
下次再調(diào)用該方法,balance字段的值將完全來自于a對(duì)象,而無需在重定向到Account了。
--]]
a:deposit(100.00)
print(a.balance) --輸出100
b = Account:new()
b:deposit(200.00)
print(b.balance) --輸出200
2. 繼承:
繼承也是面向?qū)ο笾幸粋€(gè)非常重要的概念,在Lua中我們?nèi)匀豢梢韵衲M類那樣來進(jìn)一步實(shí)現(xiàn)面向?qū)ο笾械睦^承機(jī)制,見如下代碼及關(guān)鍵性注釋:
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
--下面將派生出一個(gè)Account的子類,以使客戶可以實(shí)現(xiàn)透支的功能。
SpecialAccount = Account:new() --此時(shí)SpecialAccount仍然為Account的一個(gè)對(duì)象實(shí)例
--派生類SpecialAccount擴(kuò)展出的方法。
--下面這些SpecialAccount中的方法代碼(getLimit/withdraw),一定要位于SpecialAccount被Account構(gòu)造之后。
function SpecialAccount:getLimit()
--此時(shí)的self將為對(duì)象實(shí)例。
return self.limit or 0
end
--SpecialAccount將為Account的子類,下面的方法withdraw可以視為SpecialAccount
--重寫的Account中的withdraw方法,以實(shí)現(xiàn)自定義的功能。
function SpecialAccount:withdraw(v)
--此時(shí)的self將為對(duì)象實(shí)例。
if v - self.balance >= self:getLimit() then
error("Insufficient funds")
end
self.balance = self.balance - v
end
--在執(zhí)行下面的new方法時(shí),table s的元表已經(jīng)是SpecialAccount了,而不再是Account。
s = SpecialAccount:new{limit = 1000.00}
--在調(diào)用下面的deposit方法時(shí),由于table s和SpecialAccount均未提供該方法,因此訪問的仍然是
--Account的deposit方法。
s:deposit(100)
--此時(shí)的withdraw方法將不再是Account中的withdraw方法,而是SpecialAccount中的該方法。
--這是因?yàn)長(zhǎng)ua先在SpecialAccount(即s的元表)中找到了該方法。
s:withdraw(200.00)
print(s.balance) --輸出-100
3. 私密性:
私密性對(duì)于面向?qū)ο笳Z(yǔ)言來說是不可或缺的,否則將直接破壞對(duì)象的封裝性。Lua作為一種面向過程的腳本語(yǔ)言,更是沒有提供這樣的功能,然而和模擬支持類與繼承一樣,我們?nèi)匀豢梢栽贚ua中通過特殊的編程技巧來實(shí)現(xiàn)它,這里我們應(yīng)用的是Lua中的閉包函數(shù)。該實(shí)現(xiàn)方式和前面兩個(gè)示例中基于元表的方式有著很大的區(qū)別,見如下代碼示例和關(guān)鍵性注釋:
--和前面兩個(gè)示例不同的是,在調(diào)用對(duì)象方法時(shí),不再需要self變量,因此我們可以直接使用點(diǎn)(.),
--而不再需要使用冒號(hào)(:)操作符了。
accl = newAccount(100.00)
--在函數(shù)newAccount返回之后,該函數(shù)內(nèi)的“非局部變量”表self就不再能被外部訪問了,只能通過
--該函數(shù)返回的對(duì)象的方法來操作它們。
accl.withdraw(40.00)
print(acc1.getBalance())
事實(shí)上,上面的代碼只是給出一個(gè)簡(jiǎn)單的示例,在實(shí)際應(yīng)用中,我們可以將更多的私有變量存放于上例的局部self表中。
新聞熱點(diǎn)
疑難解答
圖片精選