Patron Décorateur
Fait partie de la section Programmation orientée objet du Journey R de Coddy. Leçon 46 sur 57.
Un décorateur encapsule quelque chose et ajoute un comportement tout en conservant la même interface. Pour une fonction, le décorateur prend une fonction et renvoie une nouvelle fonction qui effectue un travail supplémentaire autour de l’appel :
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))Sortie :
calling double with 21
[1] 42Un décorateur peut mémoriser les résultats. with_cache() conserve chaque réponse dans un environnement et n’appelle la fonction enveloppée que pour les nouveaux arguments :
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)Sortie :
results computed: 2Les objets peuvent aussi être décorés. Chaque décorateur est un objet qui contient l’objet qu’il enveloppe dans un champ et répond aux mêmes génériques, en ajoutant sa partie et en demandant le reste à l’objet interne :
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))Sortie :
coffee + milk + milk = 3Les décorateurs s’empilent et leur ordre est important : le décorateur le plus externe s’exécute en premier à l’entrée et en dernier à la sortie :
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"))Sortie :
hi ada! hi ada! / hi ada hi ada!Défi
FacileLes boissons sont agrémentées d’extras. Drink.R contient les méthodes génériques cost() et describe(), ainsi que la boisson de base, new_coffee(), qui coûte 2 et se décrit comme coffee. Dans Extras.R, écrivez trois décorateurs, chacun étant un objet qui contient la boisson qu’il enveloppe dans le champ inner :
add_milk(d): classemilk, ajoute 0.50 et+ milk;add_sugar(d): classesugar, ajoute 0.20 et+ sugar;add_syrup(d, flavour): classesyrupavec le champflavour, ajoute 0.80 et+ vanilla syrup.
Écrivez leurs méthodes cost() et describe() en interrogeant d’abord la boisson interne. Le code fourni lit des lignes telles que milk,syrup vanilla,sugar (une ligne vide correspond à un café nature) et affiche coffee + milk + vanilla syrup + sugar: 3.50.
Votre code doit être placé dans Drink.R et Extras.R. main.R contient le code fourni pour les entrées et les sorties et ne peut pas être modifié.
Essayez vous-même
source("Drink.R")
source("Extras.R")
# Code d'entrée/sortie fourni : le garder tel quel
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 = "")
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Bases de S3
Travailler avec les fichiersListes avec une classeFonctions constructricesMéthodes print et formatValidateurs et fonctions utilitairesRécapitulatif - Températures4Encapsulation dans R
Les fermetures comme objetsLes environnements comme objetsFonctions d’accèsProtéger l’étatRécapitulatif - Parcmètre2S3 : génériques et méthodes
Génériques et UseMethodMéthodes par défautMéthodes pour les génériques de baseNotions de base sur NextMethodRécapitulatif - Aires des formes5Classes S4
Définir des classes S4Slots et accèsVérifications de validitéMéthodes showRécapitulatif - Catalogue de produits8Classes de référence
Définition des classes de référenceMéthodes et mises à jour des champsSémantique de copieHéritage et callSuperRécapitulatif - File d’attente des tâches11Projet : gestion de bibliothèque
Livres et membresEmprunter des livres3Héritage S3
Vecteurs de classesOrdre de recherche des méthodesÉtendre avec NextMethodVérifier avec inherits()Récapitulatif - Paie du personnelEntraînez-vous par vous-même : Compilateur R en ligne