Menu
Coddy logo textTech

Отношение "Has-A"

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

На протяжении всего курса ты использовал наследование, чтобы разделять поведение между классами: Dog «является» Animal. Но наследование не всегда является подходящим инструментом.

Иногда у объектов нет общего семейного дерева; вместо этого один объект просто содержит другой. Это называется composition и моделирует отношение «имеет».

Рассмотрим автомобиль. Автомобиль — это не тип двигателя. У него есть engine. engine — это отдельный object, который находится внутри автомобиля:

local Engine = {}
Engine.__index = Engine

function Engine:new(horsepower)
    local obj = {horsepower = horsepower}
    setmetatable(obj, Engine)
    return obj
end

local Car = {}
Car.__index = Car

function Car:new(model, engine)
    local obj = {
        model = model,
        engine = engine  -- Сохранить объект Engine внутри Car
    }
    setmetatable(obj, Car)
    return obj
end

При создании машины вы передаёте существующий object engine в её конструктор:

local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)

print(myCar.engine.horsepower)  -- 200

Car не наследуется от Engine. Он просто хранит ссылку на него. Это сохраняет оба класса независимыми. Ты можешь заменить его на другой engine или использовать тот же класс engine в мотоцикле.

Composition даёт гибкость, которой не может дать наследование: вы собираете объекты из частей, а не загоняете их в жёсткую иерархию семейства.

challenge icon

Задание

Легко

Давайте создадим компьютерную систему с использованием композиции! Вместо наследования вы создадите Computer, у которого внутри есть CPU: это демонстрирует отношение «has-a».

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

  • CPU.lua: Создайте class CPU с конструктором :new(brand, speed), который сохраняет название бренда и скорость в GHz. Добавьте метод :getInfo(), возвращающий строку в формате: {brand} @ {speed}GHz
  • Computer.lua: Создайте class Computer, конструктор которого :new(model, cpu) принимает название модели и объект CPU. Computer хранит объект CPU внутри себя (композиция!). Добавьте метод :describe(), который выводит model компьютера и info его CPU.
  • main.lua: Объедините всё вместе! Считайте inputs для бренда CPU, скорости CPU и модели компьютера. Сначала создайте объект CPU, затем передайте его конструктору Computer. Наконец, вызовите метод :describe() компьютера.

Вы получите три входных значения:

  1. Бренд CPU (строка)
  2. Скорость CPU в GHz (число)
  3. Название модели компьютера (строка)

Ваш output должен отображать описание компьютера, включающее info содержащегося в нём CPU:

Model: {model}
CPU: {brand} @ {speed}GHz

Например, если inputs — это Intel, 3.5 и WorkStation, output должен быть таким:

Model: WorkStation
CPU: Intel @ 3.5GHz

Обратите внимание, что Computer не наследуется от CPU. Он просто хранит ссылку на него. Метод :describe() объекта Computer получает data CPU через сохранённый объект, показывая, как композиция позволяет создавать сложные объекты из более простых частей!

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

-- main.lua
-- Объединить всё вместе с помощью композиции

local CPU = require('CPU')
local Computer = require('Computer')

-- Считать входные данные
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()

-- TODO: Создать объект CPU с брендом и скоростью

-- TODO: Создать объект Computer с моделью и объектом CPU

-- TODO: Вызвать метод describe() компьютера, чтобы вывести результат
quiz iconПроверьте себя

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

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

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