2015-01-04 3 views
3

Я нашел этот учебник: http://lua-users.org/wiki/InheritanceTutorialНаследуйте метатаблицу (класс) и использовать его обязательный параметр конструктора

У меня метатаблица под названием Существо. Существо требует аргумента в своем конструкторе. Необходимый аргумент - это строка, которая представляет имя.

local creature = Creature(name) 
  • Существо имеет много других методов, таких как getDescription().
  • Creature's getDescription() возвращает строку: "Это существо".
  • существа getName() возвращает строку: имя

Я хочу, чтобы создать новый метатаблицы (класс) называется Player и он наследует Creature метатаблицу (класс)

  • Класс игрока перекроет только getDescription() способ.
  • Класс Player также наследует метод getName() существа.
  • Player getDescription() возвращает строку: "Это игрок".

Я хочу, чтобы иметь возможность сделать следующее:

local creature = Creature("Bob") 
print(creature:getDescription()) 
print(creature:getName()) 

local player = Player("Joey") 
print(player:getDescription()) 
print(player:getName()) 

Если печать:

Это существо
Боб
Это игроку
Joey

В основном, моя проблема в том, что для класса существа требуется аргумент, чтобы идентифицировать кого-то, имя. Его функция getName() использует значение в аргументе и печатает его. Если я собираюсь использовать Player для наследования всех функций Существа (и, если необходимо, переопределить), как мне изменить код, чтобы убедиться, что Игрок получает необходимый ему аргумент?

код взят из учебника:

-- Create a new class that inherits from a base class 
-- 
function inheritsFrom(baseClass) 

    -- The following lines are equivalent to the SimpleClass example: 

    -- Create the table and metatable representing the class. 
    local new_class = {} 
    local class_mt = { __index = new_class } 

    -- Note that this function uses class_mt as an upvalue, so every instance 
    -- of the class will share the same metatable. 
    -- 
    function new_class:create() 
     local newinst = {} 
     setmetatable(newinst, class_mt) 
     return newinst 
    end 

    -- The following is the key to implementing inheritance: 

    -- The __index member of the new class's metatable references the 
    -- base class. This implies that all methods of the base class will 
    -- be exposed to the sub-class, and that the sub-class can override 
    -- any of these methods. 
    -- 
    if baseClass then 
     setmetatable(new_class, { __index = baseClass }) 
    end 

    return new_class 
end 

ответ

3

Я хочу, чтобы иметь возможность сделать следующее:

local creature = Creature("Bob") 
print(creature:getDescription()) 
print(creature:getName()) 
-- ... 

Поддержка такого рода синтаксис использования класса, конечно, возможно в Lua - это просто вопрос о том, как использовать языковые механизмы и инструменты для достижения этого. Некоторые важные вопросы, которые необходимо решить:

  • Как будет строиться объект строительства? Какую функцию должен вызвать класс для инициализации экземпляра?
  • Как будет выглядеть экземпляр объекта с клиентского кода?
  • Как осуществляется переопределение метода?

Из вики-учебника, new_class:create() создает новый экземпляр, но не вызывает какую-либо строительства функции. Таким образом, в вашей системе ООП вам нужно будет принять решение о функции конструктора , которую предоставит клиентский код и вызовет создание класса. Например:

function new_class:create(...) 
    local instance = setmetatable({}, class_mt) 
    if new_class.__init__ then new_class.__init__(instance, ...) end 
    return instance 
end 

Здесь я просто использовать __init__ как имя конструктора, похожий на питон, но на самом деле любое имя будет работать до тех пор, как с помощью кода и создание класса кода соглашается.

Для поддержки синтаксиса создания объектов, такого как Creature("Bob"), Player("Joey"), вы можете либо выполнить их фактические вызовы функций, либо использовать метаметод __call. Используя последнее простое присвоение __call:

function inheritsFrom(baseClass) 
    local new_class = setmetatable({}, { __index = baseClass }) 
    -- ... 
    getmetatable(new_class).__call = new_class.create 
    return new_class 
end 

За последний вопрос, переопределить существующий метод, просто назначив ему новую функцию в производном классе. например. Таким образом, чтобы переопределить getDescription в Player вы можете сделать:

function Player:getDescription() 
    return "Is a player" 
end 

Сложив все вместе, inheritsFrom

function inheritsFrom(baseClass) 
    local new_class = setmetatable({}, { __index = baseClass }) 

    local class_mt = { __index = new_class } 
    function new_class:create(...) 
     local instance = setmetatable({}, class_mt) 
     if new_class.__init__ then new_class.__init__(instance, ...) end 
     return instance 
    end 

    getmetatable(new_class).__call = new_class.create 
    return new_class 
end 

Определения класса Creature + один существо экземпляра:

local Creature = inheritsFrom 
{ 
    __init__ = function(self, name) self.name = name end; 
    getDescription = function(self) return "Is a creature" end; 
    getName = function(self) return self.name end; 
} 

local bob = Creature "Bob" 
print(bob:getDescription()) 
print(bob:getName()) 

подклассов Player от Creature и переопределения getDescription:

local Player = inheritsFrom(Creature) 
function Player:getDescription() 
    return "Is a player" 
end 

local joey = Player "Joey" 
print(joey:getDescription()) 
print(joey:getName()) 

В качестве последнего замечания, библиотека Lua Penlight уже реализует class system подобное тому, что я описал выше, но гораздо больше возможностей, и полной. Если это не упражнение, подумайте над тем, чтобы использовать это вместо того, чтобы изобретать новую систему ООП lua.

Смежные вопросы