Tabelle di sola lettura
Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 46 di 70.
Le closure garantiscono una vera privacy, ma richiedono di definire i metodi all'interno del costruttore. Esiste un altro approccio per un caso d'uso diverso: rendere un oggetto di sola lettura dopo la creazione. È utile quando vuoi che i campi siano visibili ma non modificabili, come le coordinate di un punto fisso.
Il metametodo __newindex intercetta i tentativi di assegnare nuovi valori a una tabella. Facendogli bloccare tutte le assegnazioni, puoi congelare un oggetto:
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
endIl trucco consiste nell'usare una tabella proxy. I dati effettivi si trovano in data, mentre l'utente interagisce con la proxy vuota.
In lettura, __index recupera i dati da data. In scrittura, invece, viene attivato __newindex e lo blocchiamo:
local p = ImmutablePoint.new(10, 20)
print(p.x) -- 10 (la lettura funziona)
p.x = 50 -- Errore: impossibile modificare un oggetto immutabileQuesto schema è utile per gli oggetti di configurazione, le costanti matematiche o qualsiasi dato che non dovrebbe mai cambiare dopo l'inizializzazione. L'oggetto rimane completamente leggibile. Semplicemente, non puoi modificarlo.
Sfida
FacileCostruiamo una classe ImmutableConfig che crea oggetti di configurazione di sola lettura! Una volta creati, questi oggetti di configurazione dovrebbero consentire di leggere le impostazioni, ma bloccare completamente qualsiasi tentativo di modificarle.
Organizzerai il codice in due file:
ImmutableConfig.lua: crea un modulo che produce oggetti di configurazione immutabili. La funzione.new(appName, version, maxUsers)dovrebbe memorizzare internamente questi tre valori, quindi restituire una tabella proxy che consente di leggere tutti i campi ma impedisce qualsiasi modifica. Quando qualcuno tenta di modificare un valore, dovrebbe stampareError: Config is read-onlyinvece di generare un errore effettivo.main.lua: dai vita a ImmutableConfig! Leggi tre input per i valori di configurazione, crea un oggetto di configurazione, quindi dimostra che funziona correttamente:- Stampando tutti e tre i valori originali
- Tentando di modificare il campo
maxUsers(che dovrebbe attivare il messaggio di errore) - Stampando di nuovo
maxUsersper dimostrare che non è stato effettivamente modificato
Riceverai tre input:
- Il nome dell'applicazione (una stringa)
- La versione (una stringa)
- Il numero massimo di utenti (un numero)
L'output dovrebbe mostrare i valori di configurazione, l'errore quando si tenta di modificarli e la conferma che il valore è rimasto invariato:
App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}Per esempio, se gli input sono MyApp, 2.0 e 100, l'output dovrebbe essere:
App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100Ricorda: il pattern proxy usa una tabella vuota con cui interagisce l'utente, mentre i dati effettivi risiedono in una tabella interna separata. Il metametodo __index recupera i valori dalla tabella dei dati e __newindex intercetta (e blocca) qualsiasi tentativo di scrittura!
Provalo tu
-- Importa il modulo ImmutableConfig
local ImmutableConfig = require('ImmutableConfig')
-- Leggi gli input
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())
-- TODO: Crea un oggetto di configurazione usando ImmutableConfig.new()
-- TODO: Stampa tutti e tre i valori originali nel formato:
-- App: {appName}
-- Versione: {version}
-- Utenti massimi: {maxUsers}
-- TODO: Prova a modificare il campo maxUsers (questo dovrebbe generare un messaggio di errore)
-- TODO: Stampa di nuovo maxUsers per dimostrare che non è stato modificato
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Il concetto di «self»
Tabelle con funzioni«self» esplicitoLa sintassi dei due puntiPunto o due puntiRiepilogo - Spostare il punto4Progetto: Banca digitale
Configurazione del progettoMetodo di deposito2Schema del prototipo di classe
Il concetto di prototipoCollegare con __indexIl costruttore :new()Inizializzare gli attributiIstanze indipendentiRiepilogo - Fabbrica di auto5Sovraccarico degli operatori nella OOP
Sommare oggettiSottrarre oggettiConcatenare oggettiConfrontare oggetti (<, >)Ripasso - Calcoli con il portafoglio8Incapsulamento
Convenzioni di denominazioneClosure per la privacyAccesso tramite closureTabelle di sola letturaLogica di convalidaRiepilogo - Cassaforte sicura11Modelli di progettazione (base)
Funzioni factoryTabella singletonPattern IteratorObserver (listener)Riepilogo - Factory per logger3Stato e comportamento degli oggetti
Variabili di istanzaMetodi getterMetodi setterProprietà calcolateFormattazione delle stringheControlli di uguaglianzaRiepilogo - Voto dello studente6Fondamenti dell'ereditarietà
Configurare l'ereditarietàEreditare i metodiEstendere il costruttoreAggiungere metodi alla classe figliaCondiviso vs specificoRiepilogo - Gerarchia delle formeEsercitati da solo: Compilatore Lua online