2013-02-12 62 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