Переменные экземпляра
Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy — урок 12 из 70.
Добро пожаловать в новую главу, посвященную тому, как объекты управляют своими внутренними данными. Вы научились создавать классы и экземпляры — теперь пришло время изучить, как каждый экземпляр хранит и управляет своим собственным уникальным состоянием.
Переменные экземпляра — это поля, которые принадлежат исключительно одному объекту. Когда вы присваиваете значение self.something внутри метода или конструктора, эти данные живут только в этом конкретном экземпляре. Другие объекты того же класса имеют свои собственные отдельные копии.
Это становится особенно важным при хранении сложных данных, таких как таблицы. Рассмотрим систему инвентаря, где каждый персонаж носит разные предметы:
local Inventory = {}
Inventory.__index = Inventory
function Inventory:new()
local instance = {}
setmetatable(instance, self)
instance.items = {} -- Каждый экземпляр получает свою собственную пустую таблицу
return instance
end
function Inventory:addItem(item)
table.insert(self.items, item)
endКлючевая строка — instance.items = {}. Создавая новую пустую таблицу внутри конструктора, каждый объект инвентаря получает свой собственный отдельный список. Если бы вы вместо этого определили items в самой таблице класса, все экземпляры случайно использовали бы одну и ту же таблицу — добавление меча одному персонажу дало бы его всем!
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- Вывод: 1
print(#bag2.items) -- Вывод: 1Каждый инвентарь хранит свою собственную коллекцию. Этот паттерн применяется в тех случаях, когда экземпляру необходимо отслеживать данные, которые изменяются независимо: списки, счетчики или любое изменяемое состояние, уникальное для этого объекта.
Задание
ЛегкоДавайте создадим систему ShoppingCart, в которой каждая корзина хранит свой собственный отдельный список товаров. Это продемонстрирует, как переменные экземпляра изолируют данные между объектами — добавление товаров в одну корзину не повлияет на другую!
Вы организуете свой код в двух файлах:
ShoppingCart.lua: Определите классShoppingCart, где каждый экземпляр имеет свою собственную таблицуproducts. Включите:- Конструктор
:new(), который инициализирует пустой список товаров для каждой корзины - Метод
:addProduct(productName), который добавляет товар в список этой корзины - Метод
:listProducts(), который выводит каждый товар на отдельной строке
- Конструктор
main.lua: Подключите модуль ShoppingCart и создайте две отдельные корзины. Добавьте разные товары в каждую корзину, чтобы доказать, что они поддерживают независимые списки.
Вы получите четыре входных значения:
- Первый товар для добавления в корзину A
- Второй товар для добавления в корзину A
- Первый товар для добавления в корзину B
- Второй товар для добавления в корзину B
В вашем основном файле:
- Создайте две корзины для покупок:
cartAиcartB - Добавьте первые два товара в
cartA - Добавьте последние два товара в
cartB - Выведите
Cart A:, а затем перечислите товары корзины A - Выведите
Cart B:, а затем перечислите товары корзины B
Например, если на вход подаются Apple, Bread, Milk и Eggs, вывод должен быть следующим:
Cart A:
Apple
Bread
Cart B:
Milk
EggsПомните: ключом является инициализация products как новой пустой таблицы внутри конструктора. Это гарантирует, что каждый экземпляр корзины получит свой собственный отдельный список, а не будет использовать одну общую таблицу для всех корзин.
Попробуйте сами
-- Подключить модуль ShoppingCart
local ShoppingCart = require('ShoppingCart')
-- Прочитать входные данные
local product1 = io.read()
local product2 = io.read()
local product3 = io.read()
local product4 = io.read()
-- TODO: Создать две корзины для покупок: cartA и cartB
-- TODO: Добавить product1 и product2 в cartA
-- TODO: Добавить product3 и product4 в cartB
-- TODO: Вывести "Cart A:", затем вывести список товаров cartA
-- TODO: Вывести "Cart B:", затем вывести список товаров cartB
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур