Общее и уникальное
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 35 из 70.
При работе с наследованием важно понимать, где находятся те или иные данные. Некоторые атрибуты являются общими — они определены в родительском классе и доступны всем дочерним классам. Другие являются уникальными — они создаются непосредственно в дочернем классе или экземпляре.
Рассмотрим следующую иерархию:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Общее: определено в классе
function Animal:new(name)
local obj = {name = name} -- Уникальное: хранится в каждом экземпляре
setmetatable(obj, Animal)
return obj
endlocal Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Общий для всех собак
function Dog:new(name, breed)
local obj = Animal.new(Animal, name)
obj.breed = breed -- Уникально: у каждой собаки своя порода
setmetatable(obj, Dog)
return obj
endКогда вы создаете экземпляр Dog, некоторые значения существуют непосредственно в объекте, в то время как другие находятся через цепочку поиска:
local rex = Dog:new("Rex", "German Shepherd")
-- Уникально для этого экземпляра (хранится в rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"-- Общие (найдены через поиск)
print(rex.sound) -- "bark" (от Dog)
print(rex.kingdom) -- "Animalia" (от Animal)Ключевое отличие: поля, присвоенные obj в конструкторах, уникальны для каждого экземпляра, в то время как поля, определенные непосредственно в таблицах классов, являются общими для всех экземпляров этого класса и его наследников.
Задание
ЛегкоДавайте изучим, как данные передаются через иерархию наследования, создав систему классов Creature и Dragon. Вы воочию увидите, какие атрибуты являются общими для всех экземпляров, а какие — уникальными для каждого отдельного объекта.
Вы организуете свой код в трех файлах:
Creature.lua: Определите родительский класс с общим атрибутом уровня классаworld = "Fantasy Realm", который разделяют все существа. Включите конструктор:new(name), который сохраняет имя существа как атрибут экземпляра.Dragon.lua: Определите дочерний класс, который наследуется от Creature. Добавьте общий атрибут уровня классаelement = "fire", который разделяют все драконы. Ваш конструктор:new(name, color)должен вызывать родительский конструктор для имени, а затем добавлятьcolorкак уникальный атрибут экземпляра для каждого дракона.main.lua: Создайте двух разных драконов и проверьте их атрибуты, чтобы продемонстрировать разницу между общими и уникальными данными.
Вы получите два входных значения:
- Имя и цвет первого дракона, разделенные запятой (например,
Smaug,red) - Имя и цвет второго дракона, разделенные запятой (например,
Draco,gold)
В вашем основном файле создайте обоих драконов с их соответствующими именами и цветами. Затем выведите следующую информацию в строгом порядке:
nameпервого драконаcolorпервого драконаnameвторого драконаcolorвторого драконаelementпервого дракона (общий из класса Dragon)elementвторого дракона (общий из класса Dragon)worldпервого дракона (общий из класса Creature)
Например, если входные данные — Smaug,red и Draco,gold, вывод должен быть следующим:
Smaug
red
Draco
gold
fire
fire
Fantasy RealmОбратите внимание, что name и color у каждого дракона разные (уникальные атрибуты экземпляра), в то время как element и world одинаковы для обоих (общие атрибуты класса, найденные через цепочку поиска).
Шпаргалка
В иерархиях наследования атрибуты могут быть либо общими (определенными в таблице класса), либо уникальными (хранящимися в отдельных экземплярах).
Общие атрибуты определяются непосредственно в таблицах классов и доступны через цепочку поиска в метатаблице:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Общий для всех AnimalsУникальные атрибуты присваиваются объекту экземпляра (obj) в конструкторах:
function Animal:new(name)
local obj = {name = name} -- Уникально для каждого экземпляра
setmetatable(obj, Animal)
return obj
endДочерние классы могут иметь свои собственные общие атрибуты, наследуя при этом атрибуты родителя:
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Общий для всех Dogs
function Dog:new(name, breed)
local obj = Animal.new(Animal, name) -- Вызов родительского конструктора
obj.breed = breed -- Добавление уникального атрибута дочернего класса
setmetatable(obj, Dog)
return obj
endДоступ к атрибутам:
local rex = Dog:new("Rex", "German Shepherd")
-- Уникальные (хранятся непосредственно в rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"
-- Общие (найдены через поиск в метатаблице)
print(rex.sound) -- "bark" (из класса Dog)
print(rex.kingdom) -- "Animalia" (из класса Animal)Попробуйте сами
-- main.lua: Создание драконов и демонстрация общих и уникальных атрибутов
local Dragon = require('Dragon')
-- Чтение ввода для первого дракона (имя,цвет)
local input1 = io.read()
-- Чтение ввода для второго дракона (имя,цвет)
local input2 = io.read()
-- TODO: Разобрать первый ввод, чтобы извлечь имя и цвет
-- Подсказка: Используйте string.match с шаблоном "([^,]+),([^,]+)"
-- TODO: Разобрать второй ввод, чтобы извлечь имя и цвет
-- TODO: Создать первого дракона с его именем и цветом
-- TODO: Создать второго дракона с его именем и цветом
-- TODO: Вывести следующее по порядку:
-- 1. Имя первого дракона
-- 2. Цвет первого дракона
-- 3. Имя второго дракона
-- 4. Цвет второго дракона
-- 5. Элемент первого дракона (общий из класса Dragon)
-- 6. Элемент второго дракона (общий из класса Dragon)
-- 7. Мир первого дракона (общий из класса Creature)
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур