Zustand schützen
Teil des Abschnitts Objektorientierte Programmierung der R-Journey von Coddy. Lektion 20 von 57.
Ein Setter ist die einzige Stelle, an der sich ein Wert ändern kann, daher ist dies der Ort, an dem die Regeln durchgesetzt werden. Er prüft zuerst und ruft stop() auf, bevor irgendetwas geändert wird, und das Objekt bleibt gültig:
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())Ausgabe:
insufficient funds / 50lockBinding("rate", e) macht eine Variable einer Umgebung schreibgeschützt. Eine anschließende Zuweisung ist ein Fehler, während die anderen Variablen weiterhin beschreibbar bleiben:
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")Ausgabe:
cannot change value of locked binding for 'rate'
0.05 900 lockEnvironment(e) verhindert, dass neue Variablen hinzugefügt werden. Mit bindings = TRUE wird außerdem jede vorhandene Variable gesperrt, wodurch das gesamte Objekt schreibgeschützt wird:
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")
}Ausgabe:
change : cannot change value of locked binding for 'theme'
add : cannot add bindings to a locked environment local() führt Code in einer neuen Umgebung aus und gibt dessen letzten Wert zurück. Innerhalb definierte Hilfsfunktionen bleiben verborgen. So kann eine Datei eine Funktion privat halten, obwohl source() alles andere in die globale Umgebung einfügt:
circle_area <- local({
square <- function(x) x * x
function(r) pi * square(r)
})
print(round(circle_area(2), 2))
print(exists("square"))Ausgabe:
[1] 12.57
[1] FALSEAufgabe
EinfachVervollständige die Factory make_account(owner) in Account.R. Der Kontostand beginnt bei 0, und eine private Historie zeichnet jede Änderung als +50 oder -20 auf. Die zurückgegebene Liste enthält vier Funktionen:
deposit(x)bricht mitamount must be positiveab, sofernxnicht größer als 0 ist;withdraw(x)bricht mitamount must be positiveoderinsufficient fundsab;balance()gibt den Kontostand zurück;history()gibt die Historie als Zeichenvektor zurück.
Prüfe alles, bevor du etwas änderst, und verwende call. = FALSE. Der bereitgestellte Code liest den Besitzer ein, anschließend Zeilen wie dep 50 oder wd 20, gibt für jede Zeile ok oder error: und die Nachricht aus, versucht, eine Kopie der Historie zu ändern, und gibt den Kontostand sowie die Historie aus.
Dein Code gehört in Account.R. main.R enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.
Probier es selbst
source("Account.R")
# Mitgelieferter Ein-/Ausgabecode: belasse ihn unverändert
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 = "")
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1S3-Grundlagen
Arbeiten mit DateienListen mit einer KlasseKonstruktorfunktionenPrint- und Format-MethodenValidatoren und HilfsfunktionenRückblick – Temperaturen4Kapselung in R
Closures als ObjekteUmgebungen als ObjekteZugriffsfunktionenZustand schützenRückblick – Parkuhr2S3-Generics und Methoden
Generics und UseMethodStandardmethodenMethoden für Basis-GenericsGrundlagen von NextMethodWiederholung – Flächeninhalte von Formen5S4-Klassen
S4-Klassen definierenSlots und ZugriffGültigkeitsprüfungenShow-MethodenRückblick – Produktkatalog8Referenzklassen
Referenzklassen definierenMethoden und FeldänderungenKopiersemantikVererbung und callSuperZusammenfassung – Aufgabenwarteschlange11Projekt: Bibliotheksverwaltung
Bücher und MitgliederBücher ausleihenÜbe selbstständig: Online-R-Compiler