Dekorierer-Muster
Teil des Abschnitts Objektorientierte Programmierung der R-Journey von Coddy. Lektion 46 von 57.
Ein Dekorator umschließt etwas und fügt Verhalten hinzu, während dieselbe Schnittstelle beibehalten wird. Bei einer Funktion nimmt der Dekorator eine Funktion entgegen und gibt eine neue Funktion zurück, die zusätzliche Arbeit rund um den Aufruf erledigt:
with_logging <- function(f, name) {
function(x) {
cat("calling", name, "with", x, "\n")
f(x)
}
}
double <- function(x) x * 2
logged <- with_logging(double, "double")
print(logged(21))Ausgabe:
calling double with 21
[1] 42Ein Dekorator kann Ergebnisse speichern. with_cache() bewahrt jede Antwort in einer Umgebung auf und ruft die umschlossene Funktion nur für neue Argumente auf:
with_cache <- function(f) {
cache <- new.env()
function(x) {
key <- as.character(x)
if (!exists(key, envir = cache, inherits = FALSE)) assign(key, f(x), envir = cache)
get(key, envir = cache)
}
}
work <- 0
slow_square <- function(x) {
work <<- work + 1
x^2
}
fast <- with_cache(slow_square)
for (x in c(3, 4, 3, 3, 4)) fast(x)
cat("results computed:", work)Ausgabe:
results computed: 2Auch Objekte können dekoriert werden. Jeder Decorator ist ein Objekt, das das von ihm umhüllte Objekt in einem Feld enthält und auf dieselben Generics reagiert, seinen Teil hinzufügt und das innere Objekt nach dem Rest fragt:
cost <- function(d) UseMethod("cost")
describe <- function(d) UseMethod("describe")
cost.coffee <- function(d) 2
describe.coffee <- function(d) "coffee"
with_milk <- function(inner) structure(list(inner = inner), class = "milk")
cost.milk <- function(d) cost(d$inner) + 0.5
describe.milk <- function(d) paste(describe(d$inner), "+ milk")
cup <- with_milk(with_milk(structure(list(), class = "coffee")))
cat(describe(cup), "=", cost(cup))Ausgabe:
coffee + milk + milk = 3Dekoratoren werden verschachtelt, und ihre Reihenfolge ist wichtig: Der äußerste wird beim Hineinweg zuerst und beim Herausweg zuletzt ausgeführt:
exclaim <- function(f) function(s) paste0(f(s), "!")
twice <- function(f) function(s) paste(f(s), f(s))
greet <- function(name) paste("hi", name)
a <- twice(exclaim(greet))
b <- exclaim(twice(greet))
cat(a("ada"), "/", b("ada"))Ausgabe:
hi ada! hi ada! / hi ada hi ada!Aufgabe
EinfachGetränke werden mit Extras verfeinert. Drink.R enthält die generischen Funktionen cost() und describe() sowie das Basisgetränk new_coffee(), das 2 kostet und sich als coffee beschreibt. Schreibe in Extras.R drei Dekorierer, von denen jeder ein Objekt ist, das das von ihm umschlossene Getränk im Feld inner enthält:
add_milk(d): Klassemilk, addiert 0.50 und+ milk;add_sugar(d): Klassesugar, addiert 0.20 und+ sugar;add_syrup(d, flavour): Klassesyrupmit dem Feldflavour, addiert 0.80 und+ vanilla syrup.
Schreibe ihre cost()- und describe()-Methoden, indem du zuerst das innere Getränk fragst. Der bereitgestellte Code liest Zeilen wie milk,syrup vanilla,sugar (eine leere Zeile entspricht einem einfachen Kaffee) und gibt coffee + milk + vanilla syrup + sugar: 3.50 aus.
Dein Code gehört in Drink.R und Extras.R. main.R enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.
Probier es selbst
source("Drink.R")
source("Extras.R")
# Bereitgestellter Ein-/Ausgabe-Code: belasse ihn wie er ist
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
d <- new_coffee()
if (nchar(line) > 0) for (extra in strsplit(line, ",")[[1]]) {
p <- strsplit(extra, " ")[[1]]
d <- switch(p[1], milk = add_milk(d), sugar = add_sugar(d), syrup = add_syrup(d, p[2]))
}
cat(sprintf("%s: %.2f", describe(d), cost(d)), "\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