Menu
Coddy logo textTech

Таблица Singleton

Часть раздела Объектно-ориентированное программирование путешествия по Lua на Coddy. Урок 63 из 70.

Иногда вам нужен ровно один экземпляр чего-либо во всей программе: менеджер конфигурации, система журналирования или настройки игры. Создание нескольких копий вызвало бы проблемы: у какой из них правильные данные? Шаблон Singleton гарантирует, что существует только один экземпляр.

В Lua реализовать Singleton на удивление просто благодаря тому, как работают модули. Когда вы вызываете require для модуля, Lua кэширует результат. Последующие вызовы require возвращают кэшированную таблицу, а не новую.

-- GameConfig.lua
local GameConfig = {
    volume = 80,
    difficulty = "normal"
}

function GameConfig:setVolume(v)
    self.volume = v
end

return GameConfig

Теперь в любом месте вашей программы:

local config1 = require("GameConfig")
local config2 = require("GameConfig")

config1:setVolume(50)
print(config2.volume)  -- 50 (та же таблица!)

config1 и config2 ссылаются на одну и ту же таблицу. Изменения, внесённые через одну переменную, видны через другую. Это происходит автоматически, потому что Lua's require сохраняет возвращаемое значение в package.loaded и повторно использует его.

В отличие от паттерна Factory, который создаёт новые объекты, Singleton гарантирует общее состояние во всём вашем приложении. Это идеально подходит для глобальных настроек, к которым разные части вашего кода должны получать доступ и единообразно изменять их.

challenge icon

Задание

Легко

Давайте создадим менеджер настроек игры, используя паттерн Singleton! Вы создадите модуль конфигурации, который гарантирует, что каждая часть вашей программы обращается к одним и тем же настройкам: независимо от того, сколько раз он был подключен.

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

  • GameSettings.lua: Создайте модуль Singleton, который хранит конфигурацию игры. Ваша таблица настроек должна включать musicVolume (начальное значение — 70), sfxVolume (начальное значение — 100) и difficulty (начальное значение — "normal"). Добавьте три метода: :setMusicVolume(value), :setSfxVolume(value) и :setDifficulty(level) для изменения этих настроек. Не забудьте вернуть таблицу в конце модуля!
  • main.lua: Продемонстрируйте работу Singleton, подключив модуль GameSettings дважды в разные переменные. Используйте первую переменную, чтобы изменить громкость музыки и difficulty. Затем используйте вторую переменную, чтобы вывести все три настройки. Если Singleton работает правильно, обе переменные ссылаются на одну и ту же таблицу, поэтому изменения, внесённые через одну переменную, видны через другую.

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

  1. Новая громкость музыки (число)
  2. Новый уровень difficulty (строка, например "easy" или "hard")

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

Например, если входные значения — 50 и hard, вывод должен быть таким:

50
100
hard

Если входные значения — 25 и easy, вывод должен быть таким:

25
100
easy

Обратите внимание, что громкость звуковых эффектов остаётся равной значению по умолчанию — 100, поскольку мы её не изменяли, а громкость музыки и difficulty отражают изменения, внесённые через первую переменную, доказывая, что обе переменные указывают на один и тот же экземпляр Singleton!

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

-- main.lua - Демонстрация паттерна Singleton

-- Читаем входные данные
local newMusicVolume = tonumber(io.read())
local newDifficulty = io.read()

-- TODO: Подключите модуль GameSettings в переменную (например, settings1)

-- TODO: Подключите модуль GameSettings ЕЩЁ РАЗ в ДРУГУЮ переменную (например, settings2)
-- (Если Singleton работает правильно, обе переменные ссылаются на одну и ту же таблицу!)

-- TODO: Используйте ПЕРВУЮ переменную, чтобы:
--   - Установите громкость музыки в newMusicVolume
--   - Установите сложность в newDifficulty

-- TODO: Используйте ВТОРУЮ переменную для вывода настроек
-- Выведите каждое на своей строке: musicVolume, sfxVolume, difficulty
quiz iconПроверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Lua