Menu
Coddy logo textTech

Les fermetures comme objets

Fait partie de la section Programmation orientée objet du Journey R de Coddy. Leçon 17 sur 57.

Vous avez découvert les fermetures dans Logic & Flow : une fonction créée à l'intérieur d'une autre fonction conserve les variables qui l'entourent. Une fabrique de fonctions qui renvoie une liste de telles fonctions construit un objet. Ses variables locales constituent les données de l'objet, et les fonctions en sont les méthodes :

make_account <- function(balance = 0) {
  deposit <- function(x) balance <<- balance + x
  get_balance <- function() balance
  list(deposit = deposit, get_balance = get_balance)
}
acc <- make_account(100)
acc$deposit(50)
print(acc$get_balance())

Résultat :

[1] 150

Chaque appel de la fabrique réexécute son corps, de sorte que chaque objet possède ses propres variables. Modifier un compte ne modifie pas l’autre :

make_account <- function(balance = 0) {
  list(deposit = function(x) balance <<- balance + x,
       get_balance = function() balance)
}
ada <- make_account(100)
bo <- make_account(5)
ada$deposit(1)
cat(ada$get_balance(), bo$get_balance())

Résultat :

101 5

Les données sont privées. balance n’est pas un élément de la liste, donc acc$balance vaut NULL et lui affecter une valeur ne fait qu’ajouter un élément sans rapport. Les fonctions de la liste constituent toute l’interface publique de l’objet :

make_account <- function(balance = 0) {
  list(get_balance = function() balance)
}
acc <- make_account(100)
print(acc$balance)
acc$balance <- 1e6
print(acc$get_balance())

Sortie :

NULL
[1] 100

Les méthodes peuvent s’appeler les unes les autres lorsqu’elles sont définies comme fonctions locales avant la construction de la liste. Ici, add_many() réutilise add() :

make_tally <- function() {
  total <- 0
  add <- function(x) total <<- total + x
  add_many <- function(xs) for (x in xs) add(x)
  get <- function() total
  list(add = add, add_many = add_many, get = get)
}
t <- make_tally()
t$add(1)
t$add_many(c(2, 3, 4))
print(t$get())

Sortie :

[1] 10
challenge icon

Défi

Facile

Complétez la fabrique make_counter(start = 0) dans Counter.R. Elle conserve la valeur actuelle privée et renvoie une liste contenant quatre fonctions : increment() et decrement() modifient la valeur de 1, reset() la rétablit à start, et value() la renvoie.

Le code fourni lit la valeur de départ, puis les commandes +, - ou reset, et affiche la valeur après chacune d’elles. À la fin, il affiche les noms présents dans la liste renvoyée, qui ne doit contenir que les quatre fonctions.

Votre code doit être placé dans Counter.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("Counter.R")

# Code d'entrée/sortie fourni : le laisser tel quel
input <- suppressWarnings(readLines(file("stdin")))
counter <- make_counter(as.numeric(input[1]))
for (cmd in input[-1]) {
  if (cmd == "+") counter$increment()
  if (cmd == "-") counter$decrement()
  if (cmd == "reset") counter$reset()
  cat(cmd, " -> ", counter$value(), "\n", sep = "")
}
cat("fields visible: ", paste(sort(names(counter)), collapse = ", "), "\n", sep = "")
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur R en ligne