Menu
Coddy logo textTech

Соглашения об именовании

Часть раздела 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(), продолжит работать без изменений.

challenge icon

Задание

Легко

Давайте создадим класс BankAccount, который правильно сигнализирует о том, какие поля должны быть приватными, используя соглашение об именовании с подчеркиванием!

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

  • BankAccount.lua: Создайте класс, который управляет информацией о счете. Конструктор :new(ownerName, initialBalance) должен сохранять имя владельца как публичное поле (owner), а баланс — как приватное поле (_balance). Включите три метода:
    • :getBalance() — возвращает текущий баланс
    • :deposit(amount) — добавляет сумму к _balance
    • :getOwner() — возвращает имя владельца
  • main.lua: Подключите модуль BankAccount, считайте имя владельца, начальный баланс и сумму депозита из входных данных. Создайте счет, внесите депозит, а затем выведите имя владельца и итоговый баланс.

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

  1. Имя владельца
  2. Начальный баланс (число)
  3. Сумма депозита (число)

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

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}
quiz iconПроверьте себя

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

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