Menu
Coddy logo textTech

Вызов родительских методов

Часть раздела 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

Этот паттерн полезен, когда родительский метод выполняет важную работу, которую вы не хотите дублировать. Дочерний метод может запускать логику родителя в начале, в конце или даже в середине своего собственного кода, что дает вам полный контроль над тем, как комбинируются поведения.

challenge icon

Задание

Легко

Давайте создадим систему приветствия, в которой 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
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming