Переменные экземпляра
Часть раздела Объектно-ориентированное программирование путешествия по 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 = {}. Создавая новую пустую таблицу внутри конструктора, ты даёшь каждому объекту inventory отдельный список. Если бы вместо этого ты определил items в самой таблице class, все экземпляры случайно использовали бы одну и ту же таблицу: добавление меча одному персонажу выдало бы его всем!
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- Вывод: 1
print(#bag2.items) -- Вывод: 1Each inventory поддерживает свою own коллекцию. Этот шаблон применяется всякий раз, когда instance необходимо отслеживать данные, которые изменяются независимо: списки, счётчики или любое изменяемое состояние, уникальное для этого объекта.
Задание
ЛегкоСоздадим систему ShoppingCart, где each cart поддерживает собственный отдельный список products. Это продемонстрирует, как переменные экземпляра изолируют данные между объектами: добавление items в одну cart не повлияет на другую!
Вы организуете код в двух файлах:
ShoppingCart.lua: Определите classShoppingCart, где каждый instance имеет собственную таблицуproducts. Включите:- Конструктор
:new(), который инициализирует пустой список products для каждой cart - Метод
:addProduct(productName), который добавляет product в список этой cart - Метод
:listProducts(), который выводит каждый product в отдельной строке
- Конструктор
main.lua: Подключите модуль ShoppingCart и создайте две отдельные cart. Добавьте разные products в каждую cart, чтобы доказать, что они поддерживают независимые inventory.
Вы получите four inputs:
- Первый product для добавления в cart A
- Второй product для добавления в cart A
- Первый product для добавления в cart B
- Второй product для добавления в cart B
В вашем основном файле:
- Создайте две shopping cart:
cartAиcartB - Добавьте первые два products в
cartA - Добавьте последние два products в
cartB - Выведите
Cart A:, затем выведите products cart A - Выведите
Cart B:, затем выведите products cart B
Например, если inputs имеют значения Apple, Bread, Milk и Eggs, вывод должен быть таким:
Cart A:
Apple
Bread
Cart B:
Milk
EggsПомните: ключевой момент — инициализировать products как новую пустую таблицу внутри конструктора. Это гарантирует, что каждый cart instance получит собственный отдельный список, а не будет использовать одну таблицу совместно со всеми cart.
Попробуйте сами
-- Подключить модуль 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Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигурПотренируйтесь самостоятельно: Онлайн-компилятор Lua