Menu
Coddy logo textTech

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í; tú 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"

La persona que 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() pasa la llamada al método y nunca regresa: lo que devuelva el método es el resultado del genérico, y el código posterior a UseMethod() no se ejecuta. Por lo tanto, un genérico consta 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 la función genérica area() en Shape.R y, después, 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 proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

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

# Código de entrada/salida suministrado: déjalo 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