Перейти к основному содержимому

🧬 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