Menu
Coddy logo textTech

Делегирование

Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 50 из 70.

Хранение объекта внутри другого объекта — это только первый шаг. Настоящая сила композиции проявляется в delegation, когда внешний объект перенаправляет вызовы методов своим внутренним компонентам.

Подумай о запуске car. Ты не забираешься под капот и вручную не вращаешь engine. Вместо этого ты поворачиваешь key, а car handles всё остальное внутри.

В коде это означает, что класс Car предоставляет простой метод :start(), который делегирует фактическую работу двигателю:

function Car:start()
    print("Turning the key...")
    self.engine:run()  -- Делегировать внутреннему объекту
end

Машине не нужно знать, как работает двигатель. Она просто говорит двигателю выполнять свою работу. Это позволяет разделить обязанности. Класс Engine отвечает за логику двигателя, а Car координирует компоненты:

function Engine:run()
    print("Engine running at " .. self.horsepower .. " HP")
end

local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- Вывод:
-- Поворачиваю ключ...
-- Двигатель работает на 250 HP

Делегирование создаёт чистый интерфейс для пользователей вашего class. Они взаимодействуют с car, а не с его внутренними частями. Если позже вы замените реализацию engine на другую, публичный интерфейс car останется прежним: изменится только внутреннее делегирование.

challenge icon

Задание

Легко

Давайте создадим систему музыкального проигрывателя, демонстрирующую делегирование! Вы создадите компонент Speaker и MusicPlayer, который его содержит. player не будет напрямую обрабатывать sound output, вместо этого он делегирует эту ответственность своему внутреннему speaker.

Вы организуете код в трёх файлах:

  • Speaker.lua: Create класс Speaker с конструктором :new(volume), который сохраняет уровень громкости. Добавьте :playSound(trackName) method, который prints: Playing "{trackName}" at volume {volume}
  • MusicPlayer.lua: Create класс MusicPlayer, чей конструктор :new(brand, speaker) принимает название brand и объект Speaker. player сохраняет speaker внутри себя. Добавьте следующие методы:
    • :play(trackName): prints {brand} player starting..., затем delegates к method :playSound() speaker
    • :stop(): prints {brand} player stopped
  • main.lua: Bring everything together! Считайте inputs для громкости speaker, brand player и названия трека. Сначала Create Speaker, затем передайте его конструктору MusicPlayer. Вызовите method :play() player с названием трека, затем вызовите :stop().

Вы получите три inputs:

  1. Громкость speaker (число)
  2. brand музыкального player (строка)
  3. Название трека для воспроизведения (строка)

Ваш output должен показывать, как player координирует работу со своим speaker:

{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stopped

Например, если inputs — это 75, SoundMax и Summer Vibes, output должен быть таким:

SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stopped

Обратите внимание, что MusicPlayer не знает, как создавать sound. Он просто сообщает своему speaker, что нужно обработать эту часть. Это делегирование в действии: outer object предоставляет чистый интерфейс, а inner component выполняет специализированную работу!

Попробуйте сами

-- main.lua
-- Собери всё вместе!

local Speaker = require('Speaker')
local MusicPlayer = require('MusicPlayer')

-- Читаем входные данные
local volume = tonumber(io.read())
local brand = io.read()
local trackName = io.read()

-- TODO: Создай Speaker с заданным volume

-- TODO: Создай MusicPlayer с brand и speaker

-- TODO: Вызови метод play у player с track name

-- TODO: Вызови метод stop у player
quiz iconПроверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Lua