Прототипное ООП для Lua
Привет, я придумал свой велосипед для реализации прототипного подхода ООП в Lua.Основные фишки
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.Где код, Карл? Здесь