Protección del estado
Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 20 de 57.
Un setter es el único lugar donde un valor puede cambiar, por lo que es el lugar donde se hacen cumplir las reglas. Primero comprueba y llama a stop() antes de que cambie nada, y el objeto sigue siendo válido:
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())Salida:
insufficient funds / 50lockBinding("rate", e) hace que una variable de un entorno sea de solo lectura. Asignarle un valor después provoca un error, mientras que las demás variables siguen siendo modificables:
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")Salida:
cannot change value of locked binding for 'rate'
0.05 900 lockEnvironment(e) impide que se añadan nuevas variables. Con bindings = TRUE también bloquea todas las existentes, lo que hace que todo el objeto sea de solo lectura:
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")
}Salida:
change : cannot change value of locked binding for 'theme'
add : cannot add bindings to a locked environment local() ejecuta código en un entorno nuevo y devuelve su último valor. Los ayudantes definidos dentro permanecen ocultos, por lo que un archivo puede mantener privada una función aunque source() coloque todo lo demás en el entorno global:
circle_area <- local({
square <- function(x) x * x
function(r) pi * square(r)
})
print(round(circle_area(2), 2))
print(exists("square"))Salida:
[1] 12.57
[1] FALSEDesafío
FácilCompleta la fábrica make_account(owner) en Account.R. El saldo comienza en 0 y un historial privado registra cada cambio como +50 o -20. La lista devuelta tiene cuatro funciones:
deposit(x)se detiene conamount must be positivea menos quexsea mayor que 0;withdraw(x)se detiene conamount must be positiveoinsufficient funds;balance()devuelve el saldo;history()devuelve el historial como un vector de caracteres.
Comprueba antes de cambiar cualquier cosa y usa call. = FALSE. El código proporcionado lee el propietario, después las líneas dep 50 o wd 20, imprime ok o error: y el mensaje correspondiente para cada una, intenta cambiar una copia del historial e imprime el saldo y el historial.
Tu código va en Account.R. main.R contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
source("Account.R")
# Código de entrada/salida suministrado: déjalo tal como está
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 = "")
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de S3
Trabajar con archivosListas con una claseFunciones constructorasMétodos de impresión y formatoValidadores y auxiliaresRepaso: temperaturas4Encapsulación en R
Cierres como objetosEntornos como objetosFunciones de accesoProtección del estadoRepaso: parquímetro2S3 Genéricos y métodos
Genéricos y UseMethodMétodos predeterminadosMétodos para genéricos baseFundamentos de NextMethodRepaso: áreas de figuras5Clases S4
Definición de clases S4Slots y accesoComprobaciones de validezMétodos showRepaso - Catálogo de productos8Clases de referencia
Definición de clases de referenciaMétodos y actualizaciones de camposSemántica de copiaHerencia y callSuperRepaso: cola de tareas11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de R online