Proteggere lo stato
Fa parte della sezione Programmazione orientata agli oggetti del percorso R di Coddy. Lezione 20 di 57.
Un setter è l’unico punto in cui un valore può cambiare, quindi è il punto in cui far rispettare le regole. Prima controlla e chiama stop() prima che venga modificato qualsiasi elemento, così l’oggetto rimane valido:
make_account <- function(balance = 0) {
withdraw <- function(x) {
if (x <= 0) stop("amount must be positive", call. = FALSE)
if (x > balance) stop("insufficient funds", call. = FALSE)
balance <<- balance - x
}
list(withdraw = withdraw, balance = function() balance)
}
acc <- make_account(50)
msg <- tryCatch(acc$withdraw(80), error = function(e) conditionMessage(e))
cat(msg, "/", acc$balance())Output:
insufficient funds / 50lockBinding("rate", e) rende di sola lettura una variabile di un ambiente. Assegnarle un valore in seguito causa un errore, mentre le altre variabili rimangono scrivibili:
loan <- new.env()
loan$rate <- 0.05
loan$owed <- 1000
lockBinding("rate", loan)
loan$owed <- 900
msg <- tryCatch({ loan$rate <- 0; "changed" }, error = function(e) conditionMessage(e))
cat(msg, "\n")
cat(loan$rate, loan$owed, "\n")Output:
cannot change value of locked binding for 'rate'
0.05 900 lockEnvironment(e) impedisce di aggiungere nuove variabili. Con bindings = TRUE blocca anche tutte quelle esistenti, rendendo l'intero oggetto di sola lettura:
cfg <- new.env()
cfg$theme <- "dark"
lockEnvironment(cfg, bindings = TRUE)
for (step in c("change", "add")) {
msg <- tryCatch({
if (step == "change") cfg$theme <- "light" else cfg$size <- 12
"done"
}, error = function(e) conditionMessage(e))
cat(step, ":", msg, "\n")
}Output:
change : cannot change value of locked binding for 'theme'
add : cannot add bindings to a locked environment local() esegue il codice in un nuovo ambiente e restituisce il suo ultimo valore. Gli helper definiti al suo interno rimangono nascosti: è così che un file può mantenere privata una funzione anche se source() inserisce tutto il resto nell'ambiente globale:
circle_area <- local({
square <- function(x) x * x
function(r) pi * square(r)
})
print(round(circle_area(2), 2))
print(exists("square"))Output:
[1] 12.57
[1] FALSESfida
FacileCompleta la factory make_account(owner) in Account.R. Il saldo inizia da 0 e una cronologia privata registra ogni variazione come +50 o -20. La lista restituita contiene quattro funzioni:
deposit(x)si interrompe conamount must be positivea meno chexnon sia maggiore di 0;withdraw(x)si interrompe conamount must be positiveoinsufficient funds;balance()restituisce il saldo;history()restituisce la cronologia come vettore di caratteri.
Controlla prima di modificare qualsiasi cosa e usa call. = FALSE. Il codice fornito legge il proprietario, poi le righe dep 50 o wd 20, stampa ok oppure error: e il messaggio per ciascuna, prova a modificare una copia della cronologia e stampa il saldo e la cronologia.
Il tuo codice va in Account.R. main.R contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
source("Account.R")
# Codice di input/output fornito: lascialo così com'è
input <- suppressWarnings(readLines(file("stdin")))
acc <- make_account(input[1])
for (line in input[-1]) {
p <- strsplit(line, " ")[[1]]
amount <- as.numeric(p[2])
msg <- tryCatch({
if (p[1] == "dep") acc$deposit(amount) else acc$withdraw(amount)
"ok"
}, error = function(e) paste("error:", conditionMessage(e)))
cat(line, ": ", msg, "\n", sep = "")
}
h <- acc$history()
h[1] <- "tampered"
cat("balance: ", acc$balance(), "\n", sep = "")
cat("history: ", paste(acc$history(), collapse = ", "), "\n", sep = "")
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
1Nozioni di base su S3
Lavorare con i fileListe con una classeFunzioni costruttriciMetodi di stampa e formattazioneValidatori e funzioni di supportoRipasso - Temperature4Incapsulamento in R
Chiusure come oggettiAmbienti come oggettiFunzioni di accessoProteggere lo statoRiepilogo - Parcometro2Generics e metodi S3
Generics e UseMethodMetodi predefinitiMetodi per i generics di baseNozioni di base su NextMethodRiepilogo - Aree delle forme5Classi S4
Definire le classi S4Slot e accessoControlli di validitàMetodi showRiepilogo - Catalogo prodotti8Classi di riferimento
Definizione delle classi di riferimentoMetodi e aggiornamenti dei campiSemantica della copiaEreditarietà e callSuperRiepilogo - coda di attività11Progetto: Gestione della biblioteca
Libri e iscrittiPrestito dei libriEsercitati da solo: Compilatore R online