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
endDé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.
Défi
FacileConstruisons 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 :
- La température initiale en Celsius (un nombre)
- 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: 212Rappel : 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
endUtilisation :
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
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
1Le concept de « self »
Tables avec fonctions« self » expliciteLa syntaxe avec deux-pointsPoint vs deux-pointsRécapitulatif - Point mobile4Projet : Banque numérique
Configuration du projetMéthode de dépôt7Polymorphisme et Redéfinition
Redéfinition de méthodesAppeler des méthodes parentesDuck TypingInterface communeVérification du typeRécapitulatif - Rôles des employés10Projet : Gestionnaire de formes
Configuration du projetClasse Rectangle2Modèle de prototype de classe
Le concept de prototypeLiaison avec __indexLe constructeur :new()Initialisation des attributsInstances indépendantesRécapitulatif - Usine de voitures5Surcharge d'opérateurs en POO
Additionner des objetsSoustraire des objetsConcaténer des objetsComparer des objets (<, >)Récapitulatif - Calculs de portefeuille8Encapsulation
Conventions de nommageClosures pour la confidentialitéAccès via les ClosuresTables en lecture seuleLogique de validationRécapitulatif - Coffre-fort sécurisé11Patrons de conception (Lite)
Fonctions FactoryTable SingletonPatron IteratorObserver (Écouteur)Récapitulatif - Logger Factory3État et comportement des objets
Variables d'instanceMéthodes GetterMéthodes SetterPropriétés calculéesFormatage de chaînesVérifications d'égalitéRécapitulatif - Note de l'étudiant6Bases de l'héritage
Mise en place de l'héritageHériter des méthodesÉtendre le constructeurAjouter des méthodes enfantsPartagé vs UniqueRécapitulatif - Hiérarchie des formes