元表在 Lua (5.2) 中在面向对象编程中有什么作用?

我正在努力理解 metatable 在 Lua 中的工作原理以及为什么它们在创建类和继承方面需要。我发现的每一个 Lua 面向对象编程(OOP)示例都略有不同,但它们总是使用 metatable,特别是用于 __index 属性。这是我如何实现一些简单的继承:

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

据我所见,这很好地工作了。使用 metatable 如何改进我的设计呢?

点赞
用户734069
用户734069

没有人说元表(Metatables)是面向对象编程(OOP)所必须的。它们是有用的但不是必要的。

元表可以隐藏数据。我可以很容易地打破你所有的小心编码:

local dog = Chihuahua.New()
dog.sName = nil --糟了。
dog.GetName = nil --糟了。

这也会允许其他可疑的构造,例如在对象中存储其他数据:dog.newVar = foo

OOP不仅仅是继承。好的OOP应该也包括封装,以避免意外滥用对象。使用元表可以通过在主表中使用空表并通过__index__newindex元方法过滤所有的设置和获取来实现这一点。这样,只有对象才可以在实际表中存储数据。除非你提供了显式的访问,否则只有对象才能获取数据。

2013-02-12 18:34:40