Привет, я придумал свой велосипед для реализации прототипного подхода ООП в Lua.
Основные фишки
Перейдем сразу к примерам.
Как видим, вся магия заключается в методе extend(traits..., f), который расширяет текущий объект.
Можно определять переменные внутри
Куда же без них…
При создании нового экземпляра через new() вызывается конструктор init()
Как я упомянул, наследование сделано как single inheritance, то есть отнаследоваться можно только от одного «класса», однако есть еще трейты, о которых поговорим чуть позже. Перегрузка методов не вызывает никаких вопросов.
Для этого надо использовать второй параметр лямбда-функции, которую передаете в extend, которая есть ссылка на родительский объект (который хотим расширить)
Когда не хватает множественного наследования как в С++, можете воспользоваться трейтами, которые расширяют функционал.
Просто передайте ваши трейты в начало аргументов extend()
is_instanceof(self, instance) — вернет true, если instance является прямым или непрямым наследником self
is_typeof(self, instance) — вернет true, если instance является прямым наследником self
Как альтернатива, поддерживается работа в LuaJIT.
Здесь
Основные фишки
- Single inheritance
- Traits
- LuaJIT
Перейдем сразу к примерам.
-- подключаем модуль
local object = require("object")
-- определяем наш класс, который на самом деле объект
local HelloClass = object:extend(function(class)
-- конструктор (необязательно)
function class:init(name)
self.name = name
end
-- метод класса
function class:sayHello()
print("Hello " .. self.name)
end
end)
local hello = HelloClass:new("John")
hello:sayHello()
Как видим, вся магия заключается в методе extend(traits..., f), который расширяет текущий объект.
Можно определять переменные внутри
local object = require("object")
local Status = object:extend(function(status)
status.HTTP_200_OK = {200, "OK"}
status.HTTP_405_METHOD_NOT_ALLOWED = {404, "Method not allowed"}
end)
print(Status.HTTP_200_OK[2])
Статические методы
Куда же без них…
local object = require("object")
local MathUtils = object:extend(function(class)
function class.square(x)
return x * x
end
end)
-- вызываем статический метод
print(MathUtils.square(10))
-- вызывает тот же метод но уже через инстанс
print(MathUtils:new().square(10)) -- 100
Конструктор
При создании нового экземпляра через new() вызывается конструктор init()
local Counter = object:extend(function(class)
-- конструктор, который принимает какой-то параметр (может быть много параметров)
function class:init(initial)
self.ticks = initial or 0
end
function class:tick()
self.ticks = self.ticks + 1
end
function class:getTicks()
return self.ticks
end
end)
local c = Counter:new()
c.tick()
c.tick()
print(c:getTicks() == 2)
Наследование и перегрузка методов
Как я упомянул, наследование сделано как single inheritance, то есть отнаследоваться можно только от одного «класса», однако есть еще трейты, о которых поговорим чуть позже. Перегрузка методов не вызывает никаких вопросов.
local Shape = object:extend(function(class)
function class:getArea()
return 0
end
end)
local Square = Shape:extend(function(class)
function class:init(side)
self.side = side
end
-- перегружаем метод
function class:getArea()
return self.side * self.side
end
end)
local sq = Square:new(10)
print("Area = " .. sq:getArea())
Вызов родительского метода
Для этого надо использовать второй параметр лямбда-функции, которую передаете в extend, которая есть ссылка на родительский объект (который хотим расширить)
local Foo = object:extend(function(class)
function class:init(value)
self.value = value
end
function class:say()
print("Hello " .. self.value)
end
end)
class Bar = Foo:extend(function(class, parent)
function class:init(value)
-- вызывает конструктор родителя
parent.init(self, value)
end
end)
local foo = Foo:new("World")
foo:say() -- напечатает "Hello World"
local bar = Bar:new("World")
bar:say() -- напечатает "Hello World"
Трейты
Когда не хватает множественного наследования как в С++, можете воспользоваться трейтами, которые расширяют функционал.
Просто передайте ваши трейты в начало аргументов extend()
local TraitX = function(trait)
function trait:setX(x)
self.x = x
return self
end
function trait:getX()
return self.x
end
end
local A = object:extend(TraitX, function(class)
function class:say()
print(self.x)
end
end)
A:new():setX(10):say()
Полезные функции
is_instanceof(self, instance) — вернет true, если instance является прямым или непрямым наследником self
local ClassA = object:extend()
local ClassB = object:extend()
local obj_a = ClassA:new()
local obj_b = ClassB:new()
print(obj_a:is_instanceof(ClassA)) -- true
print(obj_a:is_instanceof(object)) -- true
print(obj_a:is_instanceof(ClassB)) -- false
is_typeof(self, instance) — вернет true, если instance является прямым наследником self
local ClassA = object:extend()
local ClassB = object:extend()
local obj_a = ClassA:new()
local obj_b = ClassB:new()
print(obj_b:is_typeof(ClassA)) -- false
print(obj_b:is_typeof(ClassB)) -- true
LuaJIT
Как альтернатива, поддерживается работа в LuaJIT.
Где код, Карл?
Здесь
Комментарии (4)
darkstar
30.05.2015 13:35Ну вы хоть напишите какая версия lua поддерживается. 5.1?5.2?5.3 only? luajit — ок, а kahlua, а luaj?
mwizard
Программист на Фортране может писать на Фортране на любом языке программирования :)