2013-02-12 26 views
4

我很努力地理解metatables是如何工作的以及爲什麼他們需要在Lua中創建類和繼承。我爲Lua找到的每個OOP示例都與上一次有所不同,但它們始終使用metatables,特別是對於__index屬性。下面是我如何實現一些簡單的繼承:用於面向對象的Lua(5.2)中的metatables有什麼用途?

Animal = {} 

function Animal.New() 
    local self = {} 
    self.sName = "Generic Animal" 

    self.GetName = function(self) 
    return self.sName 
    end 

    self.Speak = function(self) 
    -- Do nothing, abstract function 
    end 

    return self 
end 

Dog = {} 

function Dog.New() 
    local self = Animal.New() 
    self.sName = "Dog" 

    self.Speak = function(self) 
    print("Bark!") 
    end 

    return self 
end 

Labrador = {} 

function Labrador.New() 
    local self = Dog.New() 
    self.sName = "Labrador" 
    return self 
end 

Chihuahua = {} 

function Chihuahua.New() 
    local self = Dog.New() 
    self.sName = "Chihuahua" 

    self.Speak = function(self) 
    print("Yap yap!") 
    end 

    return self 
end 

-- Test -- 

l = Labrador.New() 
print(l:GetName()) 
l:Speak() 

c = Chihuahua.New() 
print(c:GetName()) 
c:Speak() 

d = Dog.New() 
print(d:GetName()) 
d:Speak() 

a = Animal.New() 
print(a:GetName()) 
a:Speak() 

輸出:

Labrador 
Bark! 
Chihuahua 
Yap yap! 
Dog 
Bark! 
Generic Animal 

所以就我所看到的,這工作得很好。如何使用metatables改進我的設計?

+1

你有沒有讀過Lua編程的第13章和第16章,它給出了我所知道的最好的解釋。在線版本爲5.0,但我認爲基本原理仍然是一樣的。 http://www.lua.org/pil/13.html – 2013-02-12 17:09:17

+0

我在Google搜索中沒有遇到特定章節(13)。這對於更好地理解metatables非常有幫助。謝謝。 – 2013-02-13 13:10:07

回答

1

沒有人說OAT需要metatables 需要。他們有用,不是必需的。

Metatables允許您隱藏數據。我能打破所有的你的細心編碼很容易:

local dog = Chihuahua.New() 
dog.sName = nil --Oops. 
dog.GetName = nil --Oops. 

這也讓其它可疑的結構,如在對象存儲的其他數據:dog.newVar = foo

OOP不僅僅是繼承。良好的面向對象也應該包含encapsulation,以保持對象的完整性以防意外誤用。 Metatables允許您通過爲主表使用空表並過濾所有設置並獲取__index__newindex元方法來完成此操作。這樣,只有對象可以將數據存儲在實際的表中。只有對象可以檢索它,除非你提供明確的訪問權限。

+0

嗯,我明白你對封裝的看法,但是真的在Lua中,儘管有人盡了最大的努力,但是阻止另一位程序員將事情搞亂是沒有多大作用的?無論你如何封裝,它仍然可以像「奇瓦瓦州=零」一樣簡單。另外,我還沒有機會對它進行測試,但是,儘管將它們連接到metatable,您是否仍然弄不清函數定義?換句話說,不管'Chihuahua:GetName'仍然被設置爲零,無論它是否是metatable的一部分? – 2013-02-13 13:12:28

+0

@JoeS:廢話; Lua有辦法阻止Chihuahua = nil工作。你所要做的就是鎖定腳本的環境。而且Lua有很多方法可以做到這一點。是的,如果用戶是*確定的*,那麼他們可以通過獲取元表來破壞對象的封裝(除非你刪除'getmetatable'函數,然後它們被洗掉)。但重點不是防止惡意使用,而是*愚蠢*。總之,沒有理由不能做到這一點。 – 2013-02-13 19:35:41

+0

@尼科爾布拉斯爲什麼不設置__metatable鍵? – warspyking 2015-02-04 02:35:06