Наследование методов
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 32 из 70.
После установления связи наследования экземпляры дочернего класса автоматически получают доступ ко всем родительским методам. Это происходит через цепочку поиска Lua — когда вы вызываете метод у экземпляра, Lua просматривает каждую связанную таблицу, пока не найдет то, что вы ищете.
Рассмотрим этот пример, где Animal определяет метод :breathe():
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
end
-- Dog наследует от Animal
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new()
local obj = {}
setmetatable(obj, Dog)
return obj
endТеперь посмотрите, что произойдет, когда мы создадим Dog и вызовем метод родителя:
local buddy = Dog:new()
buddy:breathe() -- Вывод: Breathing...Класс Dog никогда не определял :breathe(), но это работает. Lua сначала проверяет buddy, ничего не находит, затем проверяет Dog, снова ничего, и, наконец, находит его в Animal. Это автоматическое наследование методов означает, что вы пишете общее поведение один раз в родительском классе, и каждый дочерний класс сразу же получает к нему доступ.
Задание
ЛегкоДавайте создадим простую иерархию существ, чтобы увидеть наследование методов в действии! Вы создадите родительский класс Animal и дочерний класс Dog, а затем продемонстрируете, что экземпляры Dog могут использовать методы, определенные только в Animal.
Вы организуете свой код в трех файлах:
Animal.lua: Определите свой родительский класс, используя стандартный паттерн классов. Включите конструктор:new(name), который сохраняет имя животного, и метод:speak(), который выводит имя животного, за которым следуетmakes a sound. Верните класс в конце файла.Dog.lua: Определите свой дочерний класс, который наследуется от Animal. Подключите модуль Animal и настройте связь наследования, чтобы Dog мог обращаться к методам Animal. Включите конструктор:new(name), который сохраняет имя и устанавливает Dog в качестве метатаблицы. Класс Dog НЕ должен определять собственный метод:speak()— он унаследует его от Animal.main.lua: Подключите модуль Dog, считайте имя из входных данных, создайте экземпляр Dog с этим именем и вызовите для него метод:speak().
Вы получите один входной параметр: имя собаки.
Например, если на вход подается Buddy, вывод должен быть следующим:
Buddy makes a soundМагия здесь заключается в том, что ваш класс Dog никогда не определяет :speak(), однако вызов этого метода для экземпляра Dog работает идеально. Lua следует по цепочке поиска от экземпляра Dog к классу Dog, а затем к классу Animal, где и находит метод. Это и есть наследование в действии!
Шпаргалка
Экземпляры дочернего класса автоматически получают доступ ко всем родительским методам через цепочку поиска Lua. Когда метод вызывается у экземпляра, Lua ищет его в каждой связанной таблице, пока не найдет.
Настройка наследования
Определение родительского класса:
local Animal = {}
Animal.__index = Animal
function Animal:new()
local obj = {}
setmetatable(obj, Animal)
return obj
end
function Animal:breathe()
print("Breathing...")
endДочерний класс со связью наследования:
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new()
local obj = {}
setmetatable(obj, Dog)
return obj
endИспользование унаследованных методов
Дочерние экземпляры могут вызывать родительские методы, даже если они не определены в дочернем классе:
local buddy = Dog:new()
buddy:breathe() -- Output: Breathing...Цепочка поиска: Lua проверяет buddy → Dog → Animal, пока метод не будет найден.
Организация классов в нескольких файлах
Файл родительского класса (Animal.lua):
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
return AnimalФайл дочернего класса (Dog.lua):
local Animal = require("Animal")
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = {name = name}
setmetatable(obj, Dog)
return obj
end
return DogИспользование в основном файле:
local Dog = require("Dog")
local buddy = Dog:new("Buddy")
buddy:speak() -- Output: Buddy makes a soundПопробуйте сами
-- main.lua: Точка входа
local Dog = require('Dog')
-- Считать имя собаки из ввода
local name = io.read()
-- TODO: Создать экземпляр Dog с заданным именем
-- TODO: Вызвать метод :speak() у экземпляра собаки
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур