Соглашения об именовании
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 43 из 70.
В Lua все поля таблиц по умолчанию являются общедоступными. Любой может прочитать или изменить self.health напрямую. Хотя Lua не обеспечивает приватность принудительно, программисты используют соглашения об именовании для передачи намерений — указывая, какие поля следует рассматривать как детали внутренней реализации.
Стандартное соглашение заключается в том, чтобы добавлять префикс в виде нижнего подчеркивания к приватным полям:
local Player = {}
Player.__index = Player
function Player:new(name)
local obj = {
name = name, -- Публичное: можно обращаться напрямую
_health = 100, -- Приватное: используйте методы вместо этого
_score = 0 -- Приватное: внутреннее отслеживание
}
setmetatable(obj, Player)
return obj
end
function Player:getHealth()
return self._health
end
function Player:takeDamage(amount)
self._health = self._health - amount
endНижнее подчеркивание не меняет принцип работы Lua — player._health все еще технически доступно. Тем не менее, оно служит четким предупреждением для других программистов (и для вас в будущем): «Это поле предназначено для внутреннего использования. Вместо этого обращайтесь к нему через методы».
Это соглашение важно, потому что оно отделяет интерфейс (то, что должны использовать другие) от реализации (того, как это работает внутри). Если позже вам понадобится добавить валидацию или изменить способ хранения здоровья, вы измените только методы — код, использующий :getHealth(), продолжит работать без изменений.
Задание
ЛегкоДавайте создадим класс BankAccount, который правильно сигнализирует о том, какие поля должны быть приватными, используя соглашение об именовании с подчеркиванием!
Вы организуете свой код в двух файлах:
BankAccount.lua: Создайте класс, который управляет информацией о счете. Конструктор:new(ownerName, initialBalance)должен сохранять имя владельца как публичное поле (owner), а баланс — как приватное поле (_balance). Включите три метода::getBalance()— возвращает текущий баланс:deposit(amount)— добавляет сумму к_balance:getOwner()— возвращает имя владельца
main.lua: Подключите модуль BankAccount, считайте имя владельца, начальный баланс и сумму депозита из входных данных. Создайте счет, внесите депозит, а затем выведите имя владельца и итоговый баланс.
Вы получите три входных значения:
- Имя владельца
- Начальный баланс (число)
- Сумма депозита (число)
Ваш вывод должен состоять из двух строк, показывающих владельца и итоговый баланс после депозита:
Owner: {ownerName}
Balance: {finalBalance}Например, если входные данные — Maria, 500 и 150, вывод должен быть следующим:
Owner: Maria
Balance: 650Помните: префикс в виде подчеркивания в _balance сигнализирует другим программистам, что к этому полю следует обращаться через такие методы, как :getBalance() и :deposit(), а не напрямую. Поле owner без подчеркивания указывает на то, что к нему можно обращаться публично.
Шпаргалка
В Lua все поля таблиц по умолчанию являются общедоступными. Чтобы указать, какие поля следует рассматривать как детали внутренней реализации, используйте соглашение об именовании с подчеркиванием, добавляя перед приватными полями символ подчеркивания (_).
Подчеркивание не обеспечивает приватность принудительно — это сигнал другим программистам о том, что к полю следует обращаться через методы, а не напрямую.
local Player = {}
Player.__index = Player
function Player:new(name)
local obj = {
name = name, -- Публичное: можно обращаться напрямую
_health = 100, -- Приватное: используйте методы вместо прямого обращения
_score = 0 -- Приватное: внутреннее отслеживание
}
setmetatable(obj, Player)
return obj
end
function Player:getHealth()
return self._health
end
function Player:takeDamage(amount)
self._health = self._health - amount
endЭто соглашение отделяет интерфейс (то, что должны использовать другие) от реализации (того, как это работает внутри), что делает код более удобным в сопровождении при необходимости внесения изменений.
Попробуйте сами
-- Подключить модуль BankAccount
local BankAccount = require('BankAccount')
-- Прочитать входные данные
local ownerName = io.read()
local initialBalance = tonumber(io.read())
local depositAmount = tonumber(io.read())
-- TODO: Создать новый BankAccount с ownerName и initialBalance
-- TODO: Внести депозит, используя depositAmount
-- TODO: Вывести владельца и итоговый баланс в требуемом формате
-- Формат:
-- Owner: {ownerName}
-- Balance: {finalBalance}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур