Какой цели служат метатаблицы в Lua (5.2) для ООП?

Я изо всех сил пытаюсь понять, как работают метатаблицы и зачем они нужны в Lua для создания классов и наследования. Каждый пример ООП, который я нахожу для Lua, немного отличается от предыдущего, но они всегда используют метатаблицы, особенно для свойства __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

Так что, насколько я вижу, это работает просто отлично. Как использование метатаблиц улучшит мой дизайн?


person Joe S    schedule 12.02.2013    source источник
comment
Вы читали главы 13 и 16 книги «Программирование на Lua», там дается лучшее из известных мне объяснений. Онлайн-версия предназначена для версии 5.0, но я думаю, что основы остались прежними. lua.org/pil/13.html   -  person Jane T    schedule 12.02.2013
comment
Я не наткнулся на эту конкретную главу (13) в своих поисках Google. На самом деле это было очень полезно для лучшего понимания метатаблиц. Спасибо.   -  person Joe S    schedule 13.02.2013


Ответы (1)


Никто не говорит, что метатаблицы необходимы для ООП. Они полезны, но не обязательны.

Метатаблицы позволяют скрывать данные. Я могу очень легко сломать весь ваш тщательный код:

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

Это также позволило бы использовать другие сомнительные конструкции, такие как хранение других данных в объекте: dog.newVar = foo.

ООП — это больше, чем просто наследование. Хороший ООП также должен включать инкапсуляцию, чтобы поддерживать целостность объекта от случайное неправильное использование. Метатаблицы позволяют вам сделать это, используя пустую таблицу для основной таблицы и фильтруя все настройки и используя метаметоды __index и __newindex. Таким образом, только объект может хранить данные в фактической таблице. И только объект может получить его, если вы не предоставите явный доступ.

person Nicol Bolas    schedule 12.02.2013
comment
Хмммм, я понимаю, что вы говорите об инкапсуляции, но на самом деле в Lua, несмотря на все усилия, вы мало что можете сделать, чтобы помешать другому программисту все испортить, верно? Независимо от того, как вы инкапсулируете вещи, это может быть так же просто, как Chihuahua = nil. Кроме того, у меня еще не было возможности протестировать это, но не можете ли вы все еще испортить определения функций и тому подобное, несмотря на то, что они подключены к метатаблице? Другими словами, нельзя ли Chihuahua:GetName по-прежнему устанавливать значение nil независимо от того, является ли он частью метатаблицы или нет? - person Joe S; 13.02.2013
comment
@JoeS: Чепуха; У Lua есть способы предотвратить работу даже Chihuahua = nil. Все, что вам нужно сделать, это заблокировать среду сценария. И у Lua есть много способов сделать это. Да, если пользователь определен, то он может нарушить инкапсуляцию объекта, извлекая метатаблицу (если вы не удалите функцию getmetatable. Тогда они попадут в шланг). Но дело не в предотвращении злонамеренного использования, а в глупости. Короче говоря, нет причин, по которым вы не можете этого сделать. - person Nicol Bolas; 13.02.2013