Tables en lecture seule
Fait partie de la section Programmation orientée objet du Journey Lua de Coddy. Leçon 46 sur 70.
Les fermetures assurent une véritable confidentialité, mais elles nécessitent de définir les méthodes à l’intérieur du constructeur. Il existe une autre approche pour un cas d’utilisation différent : rendre un objet en lecture seule après sa création. Cela est utile lorsque vous souhaitez que les champs soient visibles mais impossibles à modifier, comme les coordonnées d’un point fixe.
La métaméthode __newindex intercepte les tentatives d’affectation de nouvelles valeurs à une table. En la faisant bloquer toutes les affectations, vous pouvez geler un objet :
local ImmutablePoint = {}
function ImmutablePoint.new(x, y)
local data = {x = x, y = y}
local proxy = {}
setmetatable(proxy, {
__index = data,
__newindex = function()
error("Cannot modify immutable object")
end
})
return proxy
endL’astuce consiste à utiliser une table proxy. Les données réelles se trouvent dans data, tandis que l’utilisateur interagit avec la proxy vide.
Lors de la lecture, __index récupère les données depuis data. Lors de l’écriture, __newindex se déclenche à la place, et nous le bloquons :
local p = ImmutablePoint.new(10, 20)
print(p.x) -- 10 (la lecture fonctionne)
p.x = 50 -- Erreur : Impossible de modifier un objet immuableCe modèle est utile pour les objets de configuration, les constantes mathématiques ou toute donnée qui ne doit jamais changer après son initialisation. L’objet reste entièrement lisible. Vous ne pouvez simplement pas le modifier.
Défi
FacileConstruisons une classe ImmutableConfig qui crée des objets de configuration en lecture seule ! Une fois créés, ces objets de configuration doivent permettre de lire leurs paramètres, tout en bloquant complètement toute tentative de modification.
Vous organiserez votre code sur deux fichiers :
ImmutableConfig.lua: créez un module qui produit des objets de configuration gelés. Votre fonction.new(appName, version, maxUsers)doit stocker ces trois valeurs en interne, puis renvoyer une table proxy qui permet de lire tous les champs, mais empêche toute modification. Lorsque quelqu'un essaie de modifier une valeur, le programme doit afficherError: Config is read-onlyau lieu de lever une véritable erreur.main.lua: donnez vie à votre ImmutableConfig ! Lisez trois entrées pour les valeurs de configuration, créez un objet de configuration, puis démontrez qu'il fonctionne correctement en :- affichant les trois valeurs d'origine ;
- tentant de modifier le champ
maxUsers(ce qui doit déclencher le message d'erreur) ; - affichant à nouveau
maxUserspour prouver qu'il n'a pas réellement été modifié.
Vous recevrez trois entrées :
- Le nom de l'application (une chaîne de caractères)
- La version (une chaîne de caractères)
- Le nombre maximal d'utilisateurs (un nombre)
Votre sortie doit afficher les valeurs de configuration, l'erreur lors de la tentative de modification et la confirmation que la valeur est restée inchangée :
App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}Par exemple, si les entrées sont MyApp, 2.0 et 100, la sortie doit être :
App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100Souvenez-vous : le modèle du proxy utilise une table vide avec laquelle l'utilisateur interagit, tandis que les données réelles résident dans une table interne distincte. La métaméthode __index récupère les données depuis la table de données, et __newindex intercepte (et bloque) toute tentative d'écriture !
Essayez vous-même
-- Importer le module ImmutableConfig
local ImmutableConfig = require('ImmutableConfig')
-- Lire les entrées
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())
-- TODO: Créer un objet config en utilisant ImmutableConfig.new()
-- TODO: Afficher les trois valeurs d'origine au format :
-- App: {appName}
-- Version: {version}
-- Max Users: {maxUsers}
-- TODO: Tenter de modifier le champ maxUsers (cela devrait déclencher un message d'erreur)
-- TODO: Afficher maxUsers à nouveau pour prouver qu'il n'a pas été modifié
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