Переопределение методов
Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 37 из 70.
До сих пор дочерние классы наследовали методы родительских классов и добавляли новые. Но что, если дочернему классу нужно то же имя метода, но с другим поведением? Это называется переопределением метода.
Когда вы определяете method в child class с тем же именем, что и у method в parent class, версия child получает приоритет. Цепочка поиска Lua сначала проверяет child class; если находит там method, прекращает поиск.
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
-- Dog переопределяет speak()
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:speak()
print(self.name .. " barks: Woof!")
endТеперь каждый class по-разному реагирует на один и тот же вызов method:
local generic = Animal:new("Creature")
local buddy = Dog:new("Buddy")
generic:speak() -- Вывод: Creature издаёт звук
buddy:speak() -- Вывод: Buddy лает: Woof!Dog полностью заменяет версию родителя для экземпляров Dog. Это позволяет создавать специализированное поведение, сохраняя единый интерфейс: каждое животное может использовать :speak(), но каждый вид делает это по-своему.
Задание
ЛегкоДавайте создадим небольшое животное царство, где разные существа говорят по-своему! Вы создадите родительский класс Animal и два дочерних класса, Cat и Cow, каждый из которых переопределит метод :speak() родительского класса, реализовав собственное специализированное поведение.
Вы организуете код в четырёх файлах:
Animal.lua: Ваш базовый класс с конструктором:new(name), который сохраняет имя животного. Добавьте метод:speak(), выводящий имя животного, за которым следуетmakes a sound. Это поведение по умолчанию, которое дочерние классы переопределят.Cat.lua: Дочерний класс, который наследуется от Animal. Его конструктор:new(name)должен вызвать конструктор родительского класса, а затем повторно связать метатаблицу с Cat. Переопределите метод:speak(), чтобы cats говорили иначе: выведите имя cat, за которым следуетmeows: Meow!Cow.lua: Ещё один дочерний класс, наследующийся от Animal. Настройте конструктор так же, как в Cat. Переопределите:speak(), чтобы cows выводили своё имя, за которым следуетmoos: Moo!main.lua: Объедините всё вместе! Считайте два имени из input, создайте Cat с первым именем и Cow со вторым именем, затем вызовите у каждого:speak(), чтобы продемонстрировать, что одно и то же имя метода даёт разный вывод в зависимости от класса.
Вы получите два входных значения:
- Имя cat
- Имя cow
В основном файле создайте обоих животных и сначала вызовите :speak() у cat, а затем у cow.
Например, если входные значения — Whiskers и Bessie, вывод должен быть таким:
Whiskers meows: Meow!
Bessie moos: Moo!Обратите внимание: оба животных реагируют на один и тот же вызов метода :speak(), но каждый выдаёт вывод, характерный для его типа. Версия Cat полностью заменяет общее поведение родительского класса "makes a sound", и Cow делает то же самое. Это переопределение метода в действии: один интерфейс, разные реализации!
Попробуйте сами
-- main.lua: Собери всё вместе
local Cat = require('Cat')
local Cow = require('Cow')
-- Прочитай ввод
local catName = io.read()
local cowName = io.read()
-- TODO: Создай Cat с первым именем
-- TODO: Создай Cow со вторым именем
-- TODO: Вызови :speak() сначала у кота, затем у коровы
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигурПотренируйтесь самостоятельно: Онлайн-компилятор Lua