Menu
Coddy logo textTech

Tabela Singleton

Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy. Lição 63 de 70.

Às vezes, você precisa de exatamente uma instância de algo em todo o seu programa: um gerenciador de configurações, um sistema de registro ou as configurações do jogo. Criar várias cópias causaria problemas: qual delas tem os dados corretos? O padrão Singleton garante que exista apenas uma instância.

Em Lua, implementar um Singleton é surpreendentemente simples graças à forma como os módulos funcionam. Quando você chama require para um módulo, Lua armazena o resultado em cache. Chamadas subsequentes a require retornam a tabela armazenada em cache, não uma nova.

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

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

return GameConfig

Agora, em qualquer lugar do seu programa:

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

config1:setVolume(50)
print(config2.volume)  -- 50 (mesma tabela!)

Tanto config1 quanto config2 fazem referência exatamente à mesma tabela. As alterações feitas por meio de uma variável ficam visíveis através da outra. Isso acontece automaticamente porque o require do Lua armazena o valor retornado em package.loaded e o reutiliza.

Ao contrário do padrão Factory, que cria novos objetos, um Singleton garante um estado compartilhado em toda a sua aplicação. Isso é ideal para configurações globais que várias partes do seu código precisam acessar e modificar de forma consistente.

challenge icon

Desafio

Fácil

Vamos criar um gerenciador de configurações de jogo usando o padrão Singleton! Você criará um módulo de configuração que garante que todas as partes do seu programa acessem exatamente as mesmas configurações, não importa quantas vezes ele seja requerido.

Você organizará seu código em dois arquivos:

  • GameSettings.lua: crie um módulo Singleton que armazene a configuração do jogo. Sua tabela de configurações deve incluir musicVolume (começando em 70), sfxVolume (começando em 100) e difficulty (começando em "normal"). Adicione três métodos: :setMusicVolume(value), :setSfxVolume(value) e :setDifficulty(level) para modificar essas configurações. Lembre-se de retornar a tabela no final do módulo!
  • main.lua: demonstre que o Singleton funciona requerendo seu módulo GameSettings duas vezes em variáveis diferentes. Use a primeira variável para alterar o volume da música e a dificuldade. Em seguida, use a segunda variável para imprimir as três configurações. Se o Singleton estiver funcionando corretamente, ambas as variáveis farão referência à mesma tabela, portanto as alterações feitas por meio de uma estarão visíveis por meio da outra.

Você receberá duas entradas:

  1. Novo volume da música (um número)
  2. Novo nível de dificuldade (uma string como "easy" ou "hard")

Depois de modificar as configurações por meio da primeira variável, imprima as três configurações usando a segunda variável, cada uma em sua própria linha, nesta ordem: volume da música, volume dos efeitos sonoros e, em seguida, dificuldade.

Por exemplo, se as entradas forem 50 e hard, a saída deverá ser:

50
100
hard

Se as entradas forem 25 e easy, a saída deverá ser:

25
100
easy

Observe que o volume dos efeitos sonoros permanece em seu valor padrão de 100, pois nunca o alteramos, mas o volume da música e a dificuldade refletem as alterações feitas por meio da primeira variável, comprovando que ambas as variáveis apontam para a mesma instância Singleton!

Experimente você mesmo

-- main.lua - Demonstra o padrão Singleton

-- Ler entradas
local newMusicVolume = tonumber(io.read())
local newDifficulty = io.read()

-- TODO: Requeira o módulo GameSettings em uma variável (ex.: settings1)

-- TODO: Requeira o módulo GameSettings NOVAMENTE em uma variável DIFERENTE (ex.: settings2)
-- (Se o Singleton funcionar corretamente, ambas as variáveis referenciam a mesma table!)

-- TODO: Use a PRIMEIRA variável para:
--   - Defina o volume da música para newMusicVolume
--   - Defina a dificuldade para newDifficulty

-- TODO: Use a SEGUNDA variável para imprimir as configurações
-- Imprima cada um em sua própria linha: musicVolume, sfxVolume, difficulty
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Lua online