Menu
CoddyTech

Genéricos y UseMethod

Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 7 de 57.

Un genérico es una función cuyo cuerpo es UseMethod("name"). Cuando se llama, examina la clase de su primer argumento y llama al método name.class. print() y format() funcionan así; también puedes escribir tus propios genéricos:

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))

Salida:

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

Quien llama escribe una llamada, y cada objeto responde a su manera. Esto es polimorfismo: el código que recorre una lista mixta no necesita un if para cada clase:

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")

Salida:

Rex says woof 
Tom says meow 
Bo says woof 

Un método toma los argumentos del genérico. Dale al genérico un parámetro ... para que los métodos puedan aceptar argumentos adicionales propios, como digits para un círculo:

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))

Salida:

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

UseMethod() transfiere la llamada al método y no regresa nunca: lo que sea que devuelva el método es el resultado del genérico, y el código después de UseMethod() no se ejecuta. Por lo tanto, un genérico es de una sola línea:

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))

Salida:

[1] 10
challenge icon

Desafío

Fácil

Las formas se dividen en tres archivos. Completa area() genérico en Shape.R y luego añade los métodos area.circle() (pi por el radio al cuadrado) en Circle.R y area.rectangle() (ancho por alto) en Rectangle.R. Los constructores están dados.

El código proporcionado lee líneas circle 2 o rectangle 3 4 e imprime la clase y el área de cada forma con dos decimales: circle: 12.57.

Tu código va en Shape.R, Circle.R y Rectangle.R. main.R contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

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

# Código de entrada/salida proporcionado: mantenlo tal como está
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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de R online