Menu
Coddy logo textTech

Acesso via Closures

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

Variáveis locais privadas são inúteis se você nunca puder interagir com elas. A solução é definir métodos getter e setter dentro do construtor, onde eles têm acesso ao escopo do closure.

Como esses métodos são criados dentro de :new(), eles podem “ver” as variáveis locais. Você os atribui diretamente ao objeto:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- Variável privada
    
    local obj = {}
    
    -- Define os métodos dentro do construtor
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

Agora a variável privada count pode ser acessada, mas somente por meio dos métodos que você fornece:

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (ainda oculto!)

Observe que :getCount() e :increment() são definidos diretamente em obj, não na tabela da classe. Cada instância recebe sua própria cópia dessas funções, cada uma com acesso ao seu próprio count privado. Essa é a compensação: a privacidade verdadeira consome um pouco mais de memória, pois os métodos não são compartilhados por meio do protótipo.

challenge icon

Desafio

Fácil

Vamos criar uma classe Temperature que usa privacidade baseada em closure para armazenar um valor de temperatura em Celsius, com métodos getter e setter definidos dentro do construtor para fornecer acesso controlado!

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

  • Temperature.lua: crie uma classe na qual o valor da temperatura seja armazenado em uma variável local dentro do construtor: completamente oculto do acesso externo. O construtor :new(initialCelsius) deve armazenar a temperatura em uma variável local e, em seguida, definir estes métodos diretamente na instância do objeto:
    • :getCelsius(): retorna a temperatura atual em Celsius
    • :setCelsius(value): atualiza a temperatura para um novo valor
    • :getFahrenheit(): retorna a temperatura convertida para Fahrenheit usando a fórmula: (celsius * 9/5) + 32
  • main.lua: importe seu módulo Temperature e leia dois valores da entrada: uma temperatura inicial e uma nova temperatura a ser definida. Crie uma instância de Temperature com o valor inicial, imprima as leituras em Celsius e Fahrenheit, use o setter para alterar a temperatura e imprima novamente ambas as leituras.

Você receberá duas entradas:

  1. A temperatura inicial em Celsius (um número)
  2. Uma nova temperatura a ser definida (um número)

Sua saída deve conter quatro linhas mostrando as leituras da temperatura antes e depois da alteração:

Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}

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

Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212

Lembre-se: o valor da temperatura deve ser armazenado em uma variável local dentro de :new(), não em self. Os métodos getter e setter são definidos dentro do construtor, onde podem acessar essa variável privada por meio de closure. Tentar acessar temp.celsius ou temp._celsius diretamente deve retornar nil!

Experimente você mesmo

-- Requer o módulo Temperature
local Temperature = require('Temperature')

-- Lê os valores de entrada
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: Crie uma instância de Temperature com o valor inicial

-- TODO: Imprima as leituras iniciais de Celsius e Fahrenheit

-- TODO: Use o setter para alterar a temperatura para newTemp

-- TODO: Imprima as leituras atualizadas de Celsius e Fahrenheit
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