🧬 LUA и ООП
Даже не знаю с чего начать на самом деле, язык Lua имеет из за своей универслаьности кучу классов. Он может быть, как и процедурным (этот подход чаще всего применяют), так и объектно ориентированым. Первый подход применяется ввиду низкого порога входа. Как-то был у меня случай, что я проходил собеседование на Lua Senior разработчика, было это примерно год назад (спойлер: собес я успешно завалил, не рассказав про реализацию принципов ООП в луа, я кратко сказал, что это можно сделать это при помощи метатаблиц). После этого случая как раз таки я начал знакомство с данным подходом, и извлек для себя одну вещь: каждый реализует его так, как хочет.
ООП (объектно-ориентированное программирование) - это подход к разработке программного обеспечения, основанный на концепции объектов
Кратко о структурах данных
Специально назвал так раздел, но на деле в нашем горячо любимом ЯП всего одна структура, как бы это странно ни звучало - это таблицы.
Таблицы мы можем ворочать, как захотим. Использовать, их как список с перечислениями, как массив, как клас с и т.д.
Enum:
local Color = {
Red = 1,
Green = 2,
Blue = 3
}
Array:
-- Одномерный массив
local A = {1,2,3}
-- Двумерный массив
local B = {{123, 456}, {789}, {000}}}
Грубо говоря: таблица - это универсальная структура данных, которую мы можем использовать так, как захотим и где з ахотим.
Метатаблицы и с чем их едят
Сразу же перейду к метатаблицы и постараюсь так-же кратко рассказать о них вам.
Метатаблица - "скрытая" таблица, которая является управляющей для той, за которой она закреплена
При помощи чего управляется управление таблицей
Есть заготовленый список метаметодов, которые хорошо описаны в этой статье вместе с примерами использования каждого из них.
Реализация классов
Для начала, думаю, стоит разобрать сами классы и переходить постепенно к разбору всех принципов ООП. Ниже приведен пример создания класса:
local man = setmetatable({}, {
--[[
self - метатаблица
name - имя человека
age - возраст человека
sex - пол человека
]]
-- Вот как раз таки тут, показан пример создания конструктора.
-- __call используется при вызове таблицы, как "функции".
__call = function(self, name, age, sex)
--PrintTable(self)
-- инициализируем "объект" класса
-- и выдаем ему все методы, которые были объявлены в классе
local obj = setmetatable({}, self)
obj.name = name
obj.age = age
obj.sex = sex
-- возвращает объект класса
return obj
end
})
man.name = "TestName"
man.age = 123
man.sex = "Male"
function man:getName()
return self.name
end
function man:setName(sName)
self.name = name
end
-- Объявляем поиск по метатаблице, в нашем случае это та-же таблица, которая будет присваиваться к объекту класса
man.__index = man
local manObject = man("John doe", 17, "Male")
print(manObject:getName())
Примерно таким вот методом можно создать вполне полноценный класс, который будет иметь методы. Можно, конечно упороться еще сильнее и реализовывать статические методы, модификаторы доступа и т.д. Достаточно прочто сделать отдельную таблицу с private, static методами и т.д. Уже на вкус и цвет, как говорится. Теперь рассмотрим пример с наследованием.
Полиморфизм и наследование.
Полиморфизм — реализация задач одной и той же идеи разными способ
local Person = {
name = "TestName",
age = 123,
sex = "Male",
__call = function(self, name, age, sex)
local obj = setmetatable({}, self)
obj.name = name
obj.age = age
obj.sex = sex
return obj
end
}
function Person:sayHello()
return "Hello im person " .. self.name
end
function Person:getName()
return self.name
end
function Person:setName(name)
self.name = name
end
Person.__index = Person
-- Создание дочернего класса "Man" с наследованием от "Person"
local Man = setmetatable({}, Person)
local oldConstructor = Man.__call
Man.__call = function(self, name, age)
local obj = oldConstructor(self, name, age)
obj.sex = "Male"
return obj
end
Man.__index = Man
function Man:sayHello()
return "Hello, im man " .. self.name
end
-- Создание объекта класса "Man"
local manObject = Man("John Doe", 17, "Male")
print(manObject:getName())
print(manObject.sex)
В этом примере мы создаем клаcс Person и Man, где второй будет наследовать все свойства и методы от первого. Переопределяя конструктор и метод sayHello