我正在努力理解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
所以据我所知,这很好用.如何使用metatables改进我的设计?
没有人说OOP需要metatables.它们很有用,不是必需的.Metatables允许您隐藏数据.我可以很容易地打破你所有的细致编码:
local dog = Chihuahua.New() dog.sName = nil --Oops. dog.GetName = nil --Oops.
它还允许其他可疑的构造,例如在对象中存储其他数据:dog.newVar = foo.
OOP不仅仅是继承.良好的OOP也应该包含encapsulation,以保持物体的完整性,防止意外误用. Metatables允许您通过使用主表的空表并过滤所有设置并通过__index和__newindex元方法来完成此操作.这样,只有对象可以在实际表中存储数据.除非您提供显式访问权限,否则只有对象可以检索它.
