Вызов родительских методов
Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 38 из 70.
Иногда полностью переопределять method — не то, что вам нужно. Вместо этого вы можете extends поведение parent: выполнить то, что делает parent, а затем добавить что-то ещё. Для этого можно напрямую вызвать parent method из переопределения child.
В этой технике используется точечный синтаксис с именем родительского класса, при этом self явно передаётся как первый аргумент:
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 расширяет поведение родителя
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()
Animal.speak(self) -- Сначала вызвать метод родителя
print(self.name .. " wags tail happily")
endКлючевая строка — Animal.speak(self). Используя точечный синтаксис родительского класса и передавая self вручную, мы вызываем исходный метод, прежде чем добавить собственное поведение:
local buddy = Dog:new("Buddy")
buddy:speak()
-- Вывод:
-- Buddy издаёт звук
-- Buddy радостно виляет хвостомЭтот шаблон полезен, когда parent method выполняет важную работу, которую вы не хотите дублировать. child может сначала, в конце или даже в середине своего кода выполнить логику parent, что даёт вам полный контроль над тем, как сочетаются разные варианты поведения.
Задание
ЛегкоДавайте создадим систему приветствий, в которой FormalPerson расширяет поведение обычного Person! Вместо того чтобы полностью заменять способ, которым person представляет себя, формальная версия сначала выполнит стандартное представление, а затем добавит дополнительную вежливую деталь.
Вы организуете свой код в трёх файлах:
Person.lua: ваш базовый class с конструктором:new(name), который сохраняет имя person. Добавьте метод:introduce(), который выводит имя person, за которым следуетsays hi. Это базовое поведение, которое будет расширено.FormalPerson.lua: дочерний class, который наследуется от Person. Его constructor должен вызвать parent constructor для обработки имени. Переопределите метод:introduce(), но вместо полной замены поведения parent сначала вызовите метод parent с помощьюPerson.introduce(self), а затем выведите дополнительную строку с именем person, за которым следуетbows politely.main.lua: подключите свой модуль FormalPerson, считайте имя из input, создайте instance FormalPerson и вызовите:introduce(), чтобы увидеть оба поведения вместе.
Вы получите один input: имя person.
Когда вы вызовете :introduce() у FormalPerson, он должен вывести две строки: первую — из метода parent, вторую — из дополнения child:
{name} says hi
{name} bows politelyНапример, если input — Eleanor, результатом должен быть:
Eleanor says hi
Eleanor bows politelyКлючевая идея заключается в том, что FormalPerson не дублирует логику "says hi". Он делегирует эту работу методу parent, а затем добавляет собственное уникальное поведение. Это сохраняет чистоту кода и демонстрирует, как child classes могут расширять, а не заменять функциональность parent!
Попробуйте сами
-- main.lua: Точка входа для системы приветствий
local FormalPerson = require('FormalPerson')
-- Считать имя человека из ввода
local name = io.read()
-- TODO: Создать экземпляр FormalPerson с заданным именем
-- TODO: Вызвать метод introduce у экземпляра FormalPerson
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигурПотренируйтесь самостоятельно: Онлайн-компилятор Lua