Menu
CoddyTech

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 Logique et flux : 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 sont 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())

Sortie :

[1] 150

Chaque appel de la fabrique exécute à nouveau son corps, donc chaque objet possède ses propres variables. Modifier un compte ne touche 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 assigner une valeur ajoute seulement 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 création 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 garde la valeur actuelle privée et renvoie une liste de quatre fonctions : increment() et decrement() modifient la valeur de 1, reset() la réinitialise à 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 doit contenir uniquement les quatre fonctions.

Votre code doit être placé dans Counter.R. main.R contient le code d'entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

source("Counter.R")

# Code d'entrée/sortie fourni : conservez-le 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