Menu
Coddy logo textTech

Accès via les Closures

Fait partie de la section Object Oriented Programming du Journey Lua de Coddy — leçon 45 sur 70.

Les variables locales privées sont inutiles si vous ne pouvez jamais interagir avec elles. La solution consiste à définir des méthodes getter et setter à l'intérieur du constructeur — où elles ont accès à la portée de la fermeture (closure).

Puisque ces méthodes sont créées à l'intérieur de :new(), elles peuvent « voir » les variables locales. Vous les affectez directement à l'objet :

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- Variable privée
    
    local obj = {}
    
    -- Définir les méthodes à l'intérieur du constructeur
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

Désormais, la variable privée count est accessible, mais uniquement via les méthodes que vous fournissez :

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (toujours masqué !)

Remarquez que :getCount() et :increment() sont définies directement sur obj, et non sur la table de classe. Chaque instance reçoit sa propre copie de ces fonctions, chacune ayant accès à son propre count. C'est le compromis : une véritable confidentialité coûte un peu plus de mémoire car les méthodes ne sont pas partagées via le prototype.

challenge icon

Défi

Facile

Construisons une classe Temperature qui utilise la confidentialité basée sur les fermetures (closures) pour stocker une valeur de température en Celsius, avec des méthodes getter et setter définies à l'intérieur du constructeur pour fournir un accès contrôlé !

Vous organiserez votre code sur deux fichiers :

  • Temperature.lua : Créez une classe où la valeur de la température est stockée dans une variable locale à l'intérieur du constructeur — complètement cachée de l'accès extérieur. Le constructeur :new(initialCelsius) doit stocker la température dans une variable locale, puis définir ces méthodes directement sur l'instance de l'objet :
    • :getCelsius() — retourne la température actuelle en Celsius
    • :setCelsius(value) — met à jour la température avec une nouvelle valeur
    • :getFahrenheit() — retourne la température convertie en Fahrenheit en utilisant la formule : (celsius * 9/5) + 32
  • main.lua : Importez votre module Temperature et lisez deux valeurs à partir de l'entrée : une température initiale et une nouvelle température à définir. Créez une instance de Temperature avec la valeur initiale, affichez les lectures Celsius et Fahrenheit, puis utilisez le setter pour changer la température et affichez à nouveau les deux lectures.

Vous recevrez deux entrées :

  1. La température initiale en Celsius (un nombre)
  2. Une nouvelle température à définir (un nombre)

Votre sortie doit comporter quatre lignes montrant les relevés de température avant et après le changement :

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

Par exemple, si les entrées sont 0 et 100, la sortie doit être :

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

Rappel : la valeur de la température doit être stockée dans une variable locale à l'intérieur de :new(), et non sur self. Les méthodes getter et setter sont définies à l'intérieur du constructeur où elles peuvent accéder à cette variable privée via une fermeture. Tenter d'accéder directement à temp.celsius ou temp._celsius devrait retourner nil !

Aide-mémoire

Pour créer de véritables variables privées dans les classes Lua, définissez des méthodes getter et setter à l'intérieur du constructeur où elles ont accès aux variables locales via une fermeture (closure).

Les méthodes sont assignées directement à l'instance de l'objet (et non à la table de classe), donnant à chaque instance sa propre copie avec accès à ses propres variables privées :

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- Variable privée
    
    local obj = {}
    
    -- Définir les méthodes à l'intérieur du constructeur
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

Utilisation :

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (toujours caché !)

Compromis : Chaque instance reçoit sa propre copie des méthodes (non partagées via le prototype), ce qui consomme plus de mémoire mais offre une véritable confidentialité.

Essayez vous-même

-- Requiert le module Temperature
local Temperature = require('Temperature')

-- Lit les valeurs d'entrée
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: Créer une instance de Temperature avec la valeur initiale

-- TODO: Afficher les lectures initiales en Celsius et Fahrenheit

-- TODO: Utiliser le setter pour changer la température à newTemp

-- TODO: Afficher les lectures mises à jour en Celsius et Fahrenheit
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Object Oriented Programming