Независимые экземпляры
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 10 из 70.
Важным аспектом объектно-ориентированного программирования является то, что каждый экземпляр сохраняет свое собственное отдельное состояние. Когда вы создаете два объекта одного и того же класса, они полностью независимы — изменение одного не влияет на другой.
Рассмотрим этот пример:
local Counter = {}
Counter.__index = Counter
function Counter:new(start)
local instance = {}
setmetatable(instance, self)
instance.value = start or 0
return instance
end
function Counter:increment()
self.value = self.value + 1
end
-- Создаем два отдельных счетчика
local counterA = Counter:new(10)
local counterB = Counter:new(5)
counterA:increment()
counterA:increment()
print(counterA.value) -- Вывод: 12
print(counterB.value) -- Вывод: 5Несмотря на то, что оба счетчика созданы на основе одного и того же класса Counter, инкрементирование counterA не влияет на counterB. У каждого объекта есть свое собственное поле value, хранящееся в его собственной таблице экземпляра.
Эта независимость — то, что делает объекты полезными. Вы можете создать десятки игроков в игре, каждый из которых отслеживает свое собственное здоровье и счет. Вы можете управлять несколькими банковскими счетами, каждый из которых имеет свой баланс.
Класс определяет структуру и поведение, но каждый экземпляр живет своей собственной жизнью со своими собственными данными.
Задание
ЛегкоДавайте докажем, что объекты одного и того же класса действительно живут независимой жизнью! Вы создадите класс Wallet и два отдельных экземпляра кошелька, а затем измените их независимо друг от друга, чтобы продемонстрировать, что изменения в одном не влияют на другой.
Вы организуете свой код в двух файлах:
Wallet.lua: Определите классWalletсо стандартным паттерном конструктора. Каждый кошелек должен отслеживать свой собственныйbalance. Включите:- Конструктор
:new(startingBalance), который инициализирует кошелек с заданной суммой - Метод
:add(amount), который увеличивает баланс - Метод
:spend(amount), который уменьшает баланс
- Конструктор
main.lua: Подключите модуль Wallet и создайте два отдельных экземпляра кошелька. Выполните различные операции над каждым из них, чтобы показать, что они сохраняют независимое состояние.
Вы получите четыре входных значения:
- Начальный баланс для кошелька A
- Начальный баланс для кошелька B
- Сумма для добавления в кошелек A
- Сумма для списания из кошелька B
В вашем основном файле:
- Создайте
walletAс первым начальным балансом - Создайте
walletBсо вторым начальным балансом - Добавьте указанную сумму в
walletA - Спишите указанную сумму из
walletB - Выведите оба баланса на отдельных строках
Выведите итоговые балансы в этом точном формате:
Wallet A: [balance]
Wallet B: [balance]Например, если входные данные равны 100, 50, 25 и 10, вывод должен быть следующим:
Wallet A: 125
Wallet B: 40Обратите внимание, как добавление в кошелек A не меняет кошелек B, а списание из кошелька B не влияет на кошелек A — каждый экземпляр сохраняет свой собственный отдельный баланс.
Шпаргалка
Каждый экземпляр класса поддерживает свое собственное отдельное состояние. Создание нескольких объектов одного и того же класса приводит к появлению полностью независимых экземпляров — изменение одного из них не влияет на другие.
Пример, демонстрирующий независимость экземпляров:
local Counter = {}
Counter.__index = Counter
function Counter:new(start)
local instance = {}
setmetatable(instance, self)
instance.value = start or 0
return instance
end
function Counter:increment()
self.value = self.value + 1
end
-- Создаем два отдельных счетчика
local counterA = Counter:new(10)
local counterB = Counter:new(5)
counterA:increment()
counterA:increment()
print(counterA.value) -- Вывод: 12
print(counterB.value) -- Вывод: 5Каждый объект имеет свою собственную таблицу экземпляра, в которой хранятся его данные. Класс определяет структуру и поведение, но каждый экземпляр сохраняет независимое состояние.
Попробуйте сами
-- Подключить модуль Wallet
local Wallet = require('Wallet')
-- Чтение входных данных
local startingA = tonumber(io.read())
local startingB = tonumber(io.read())
local addAmount = tonumber(io.read())
local spendAmount = tonumber(io.read())
-- TODO: Создать walletA с первым начальным балансом
-- TODO: Создать walletB со вторым начальным балансом
-- TODO: Добавить указанную сумму в walletA
-- TODO: Потратить указанную сумму из walletB
-- TODO: Вывести итоговые балансы в требуемом формате
-- Формат: "Wallet A: [balance]" и "Wallet B: [balance]"
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур