Menu
Coddy logo textTech

Переменные экземпляра

Часть раздела Object Oriented Programming путешествия по 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

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

challenge icon

Задание

Легко

Давайте создадим систему ShoppingCart, в которой каждая корзина хранит свой собственный отдельный список товаров. Это продемонстрирует, как переменные экземпляра изолируют данные между объектами — добавление товаров в одну корзину не повлияет на другую!

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

  • ShoppingCart.lua: Определите класс ShoppingCart, где каждый экземпляр имеет свою собственную таблицу products. Включите:
    • Конструктор :new(), который инициализирует пустой список товаров для каждой корзины
    • Метод :addProduct(productName), который добавляет товар в список этой корзины
    • Метод :listProducts(), который выводит каждый товар на отдельной строке
  • main.lua: Подключите модуль ShoppingCart и создайте две отдельные корзины. Добавьте разные товары в каждую корзину, чтобы доказать, что они поддерживают независимые списки.

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

  1. Первый товар для добавления в корзину A
  2. Второй товар для добавления в корзину A
  3. Первый товар для добавления в корзину B
  4. Второй товар для добавления в корзину B

В вашем основном файле:

  1. Создайте две корзины для покупок: cartA и cartB
  2. Добавьте первые два товара в cartA
  3. Добавьте последние два товара в cartB
  4. Выведите Cart A:, а затем перечислите товары корзины A
  5. Выведите Cart B:, а затем перечислите товары корзины B

Например, если на вход подаются Apple, Bread, Milk и Eggs, вывод должен быть следующим:

Cart A:
Apple
Bread
Cart B:
Milk
Eggs

Помните: ключом является инициализация products как новой пустой таблицы внутри конструктора. Это гарантирует, что каждый экземпляр корзины получит свой собственный отдельный список, а не будет использовать одну общую таблицу для всех корзин.

Шпаргалка

Переменные экземпляра — это поля, которые принадлежат исключительно одному объекту. Когда вы присваиваете значение self.something внутри метода или конструктора, эти данные живут только в этом конкретном экземпляре.

Чтобы создать переменные экземпляра, инициализируйте их внутри конструктора, используя новую таблицу для каждого экземпляра:

local Inventory = {}
Inventory.__index = Inventory

function Inventory:new()
    local instance = {}
    setmetatable(instance, self)
    instance.items = {}  -- Each instance gets its own empty table
    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)  -- Output: 1
print(#bag2.items)  -- Output: 1

Каждый экземпляр поддерживает свою собственную коллекцию независимо. Этот паттерн применим к любому изменяемому состоянию, уникальному для объекта — спискам, счетчикам или другим данным, которые меняются для каждого экземпляра.

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

-- Подключить модуль 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
quiz iconПроверьте себя

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

Все уроки раздела Object Oriented Programming