Классы и объекты ...
Конструкция tbl:func() (при объявлении функции и при ее вызове) предоставляет основные возможности, позволяющие работать с таблицей как с объектом. Основная проблема состоит в порождении многих объектов, имеющих сходное поведение т.е. порожденных от одного класса:,
PHP код:
function class()
cl = {}
cl.__index = cl -- cl будет использоваться как мета-таблица
return cl
end
function object( cl, obj )
obj = obj or {} -- а вдруг есть уже заполненные поля?
setmetatable(obj, cl)
return obj
end
Здесь функция class создает пустую таблицу, подготовленную к тому, чтобы стать мета-таблицей объекта. Методы класса делаются полями этой таблицы т.е. класс является таблицей, одновременно содержащей методы объекта и его мета-методы. Функция object() создает объект заданного класса — таблицу, у которой в качестве мета-таблицы установлен заданный класс. Во втором аргументе может быть передана таблица, содержащая проинициализированные поля объекта.
PHP код:
Some_Class = class()
function Some_Class:foo() ... end
function Some_Class:new()
return object(self, { xxx = 12 })
end
x = Some_Class:new()
x:foo()
Наследование ...
В описанной реализации мета-таблица класса остается не использованной, что делает простой задачу реализации наследования. Класс-наследник создается как объект класса, после чего в нем устанавливающая поле __index таким образом, чтобы его можно было использовать как мета-таблицу:
PHP код:
function subclass( pcl )
cl = pcl:new() -- создаем экземпляр
cl.__index = cl -- и делаем его классом
return cl
end
Теперь в полученный класс-наследник можно добавить новые поля и методы:
PHP код:
Der_Class = subclass(Some_Class)
function Der_Class:new()
local obj = object(self, Some_Class:new())
obj.yyy = 13 -- добавляем новые поля
return obj
end
function Der_Class:bar() ... end -- и новые методы
y = Der_Class:new()
y:foo()
y:bar()
Единственный нетривиальный момент здесь состоит в использовании функции new() из класса-предка с последующей заменой мета-таблицы посредством вызова функции object().
При обращении к методам объекта класса-наследника в первую очередь происходит их поиск в мета-таблице т.е. в самом классе-наследнике. Если метод был унаследован, то этот поиск окажется неудачным и произойдет обращение к мета-таблице класса-наследника т.е. к классу-предку.
Основной недостаток приведенного общего решения состоит в невозможности передачи параметров в функцию new() класса-предка.