Accès via les Closures
Fait partie de la section Programmation orientée objet 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.
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
endLa variable privée count peut maintenant être consultée, mais uniquement par l’intermédiaire des 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 caché !)Remarquez que :getCount() et :increment() sont définies directement sur obj, et non sur la table de classe. Chaque instance obtient sa propre copie de ces fonctions, chacune ayant accès à son propre count privé. C’est le compromis : une véritable confidentialité nécessite un peu plus de mémoire, puisque les méthodes ne sont pas partagées par l’intermédiaire du prototype.
Défi
FacileConstruisons une classe Temperature qui utilise la confidentialité basée sur les closures pour stocker une température en Celsius, avec des méthodes getter et setter définies à l'intérieur du constructeur afin de 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 : elle est complètement masquée de l'extérieur. Le constructeur:new(initialCelsius)doit stocker la température dans une variable locale, puis définir directement ces méthodes sur l'instance de l'objet ::getCelsius(): renvoie la température actuelle en Celsius:setCelsius(value): met à jour la température avec une nouvelle valeur:getFahrenheit(): renvoie la température convertie en Fahrenheit à l'aide de la formule :(celsius * 9/5) + 32
main.lua: exigez votre module Temperature et lisez deux valeurs saisies : une température initiale et une nouvelle température à définir. Créez une instance de Temperature avec la valeur initiale, affichez les valeurs en Celsius et en Fahrenheit, puis utilisez le setter pour modifier la température et affichez à nouveau les deux valeurs.
Vous recevrez deux entrées :
- La température initiale en Celsius (un nombre)
- Une nouvelle température à définir (un nombre)
Votre sortie doit contenir quatre lignes indiquant les valeurs de température avant et après la modification :
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: 212N'oubliez pas : 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 par l'intermédiaire d'une closure. Toute tentative d'accès direct à temp.celsius ou temp._celsius doit renvoyer nil !
Essayez vous-même
-- Requiert le module Temperature
local Temperature = require('Temperature')
-- Lire 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 Programmation orientée objet
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 RectangleClasse CercleMéthode PérimètreCollection de formesAire totaleFiltrer les formes2Modè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 formesEntraînez-vous par vous-même : Compilateur Lua en ligne