Menu
Coddy logo textTech

Génériques et UseMethod

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

Un générique est une fonction dont le corps est UseMethod("name"). Lorsqu’elle est appelée, elle examine la classe de son premier argument et appelle la méthode name.class. print() et format() fonctionnent ainsi ; vous pouvez également écrire vos propres génériques :

speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
rex <- structure(list(name = "Rex"), class = "dog")
tom <- structure(list(name = "Tom"), class = "cat")
print(speak(rex))
print(speak(tom))

Sortie :

[1] "Rex says woof"
[1] "Tom says meow"

L’appelant effectue un seul appel, et chaque objet répond à sa manière. C’est le polymorphisme : le code qui parcourt une liste mixte n’a pas besoin d’un if pour chaque classe :

speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
pets <- list(structure(list(name = "Rex"), class = "dog"),
             structure(list(name = "Tom"), class = "cat"),
             structure(list(name = "Bo"), class = "dog"))
for (p in pets) cat(speak(p), "\n")

Sortie :

Rex says woof 
Tom says meow 
Bo says woof 

Une méthode prend les arguments du générique. Donnez au générique un paramètre ... afin que les méthodes puissent accepter des arguments supplémentaires qui leur sont propres, comme digits pour un cercle :

area <- function(shape, ...) UseMethod("area")
area.square <- function(shape, ...) shape$side^2
area.circle <- function(shape, digits = 2, ...) round(pi * shape$r^2, digits)
sq <- structure(list(side = 3), class = "square")
ci <- structure(list(r = 1), class = "circle")
print(area(sq))
print(area(ci))
print(area(ci, digits = 4))

Sortie :

[1] 9
[1] 3.14
[1] 3.1416

UseMethod() transmet l’appel à la méthode et ne revient jamais : tout ce que la méthode renvoie constitue le résultat du générique, et le code qui suit UseMethod() ne s’exécute pas. Un générique tient donc en une seule ligne :

size <- function(x) {
  UseMethod("size")
  cat("this line never runs\n")
}
size.box <- function(x) x$w * x$h
b <- structure(list(w = 2, h = 5), class = "box")
print(size(b))

Sortie :

[1] 10
challenge icon

Défi

Facile

Les formes sont réparties sur trois fichiers. Complétez la fonction générique area() dans Shape.R, puis ajoutez les méthodes area.circle() (pi multiplié par le carré du rayon) dans Circle.R et area.rectangle() (largeur multipliée par hauteur) dans Rectangle.R. Les constructeurs sont fournis.

Le code fourni lit les lignes circle 2 ou rectangle 3 4 et affiche la classe et l'aire de chaque forme avec deux décimales : circle: 12.57.

Votre code doit être placé dans Shape.R, Circle.R et Rectangle.R. main.R contient le code fourni pour les entrées et sorties et ne peut pas être modifié.

Essayez vous-même

source("Shape.R")
source("Circle.R")
source("Rectangle.R")

# Code d'entrée/sortie fourni : le garder tel quel
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  s <- if (p[1] == "circle") new_circle(as.numeric(p[2])) else new_rectangle(as.numeric(p[2]), as.numeric(p[3]))
  cat(sprintf("%s: %.2f", class(s), area(s)), "\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