Отношение "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) -- 200Car не наследуется от Engine. Он просто хранит ссылку на него. Это сохраняет оба класса независимыми. Ты можешь заменить его на другой engine или использовать тот же класс engine в мотоцикле.
Composition даёт гибкость, которой не может дать наследование: вы собираете объекты из частей, а не загоняете их в жёсткую иерархию семейства.
Задание
ЛегкоДавайте создадим компьютерную систему с использованием композиции! Вместо наследования вы создадите Computer, у которого внутри есть CPU: это демонстрирует отношение «has-a».
Вы организуете свой код в трёх файлах:
CPU.lua: Создайте class CPU с конструктором:new(brand, speed), который сохраняет название бренда и скорость в GHz. Добавьте метод:getInfo(), возвращающий строку в формате:{brand} @ {speed}GHzComputer.lua: Создайте class Computer, конструктор которого:new(model, cpu)принимает название модели и объект CPU. Computer хранит объект CPU внутри себя (композиция!). Добавьте метод:describe(), который выводит model компьютера и info его CPU.main.lua: Объедините всё вместе! Считайте inputs для бренда CPU, скорости CPU и модели компьютера. Сначала создайте объект CPU, затем передайте его конструктору Computer. Наконец, вызовите метод:describe()компьютера.
Вы получите три входных значения:
- Бренд CPU (строка)
- Скорость CPU в GHz (число)
- Название модели компьютера (строка)
Ваш 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() компьютера, чтобы вывести результат
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур9Композиция и примеси
Отношение "Has-A"ДелегированиеПростые примесиПрименение нескольких примесейПримеси против наследованияИтоги — Сборка роботаПотренируйтесь самостоятельно: Онлайн-компилятор Lua