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