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