Menu
Coddy logo textTech

Despacho sobre dos argumentos

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

Un genérico S4 puede elegir su método según las clases de varios argumentos. La firma enumera una clase por argumento, por lo que cada par de clases puede tener su propio método:

setClass("Asteroid", slots = c(size = "numeric"))
setClass("Ship", slots = c(name = "character"))
invisible(setGeneric("collide", function(a, b) standardGeneric("collide")))
setMethod("collide", signature("Asteroid", "Ship"), function(a, b) paste(b@name, "is hit"))
setMethod("collide", signature("Ship", "Ship"), function(a, b) "two ships bump")
rock <- new("Asteroid", size = 3)
enterprise <- new("Ship", name = "Enterprise")
print(collide(rock, enterprise))
print(collide(enterprise, enterprise))

Salida:

[1] "Enterprise is hit"
[1] "two ships bump"

La clase "ANY" coincide con todas las clases. Un método para signature("ANY", "ANY") es la alternativa de reserva que se ejecuta cuando no encaja ningún par más específico:

setClass("Ship", slots = c(name = "character"))
invisible(setGeneric("collide", function(a, b) standardGeneric("collide")))
setMethod("collide", signature("Ship", "Ship"), function(a, b) "two ships bump")
setMethod("collide", signature("ANY", "ANY"), function(a, b) "nothing happens")
s <- new("Ship", name = "A")
cat(collide(s, s), "/", collide(s, 42), "/", collide("x", "y"))

Salida:

two ships bump / nothing happens / nothing happens

El orden de los argumentos importa: signature("A", "B") y signature("B", "A") son métodos diferentes. Las clases básicas, como numeric y character, también pueden aparecer en una firma:

invisible(setGeneric("join", function(x, y) standardGeneric("join")))
setMethod("join", signature("character", "numeric"), function(x, y) paste(x, "number", y))
setMethod("join", signature("numeric", "character"), function(x, y) paste(y, "after number", x))
print(join("item", 3))
print(join(3, "item"))

Salida:

[1] "item number 3"
[1] "item after number 3"

La clase "missing" en una signatura coincide con un argumento que no se proporcionó en absoluto, por lo que un genérico puede ofrecer una forma corta y una larga:

invisible(setGeneric("greet", function(name, greeting) standardGeneric("greet")))
setMethod("greet", signature("character", "missing"), function(name, greeting) paste("Hello,", name))
setMethod("greet", signature("character", "character"), function(name, greeting) paste0(greeting, ", ", name))
print(greet("Ada"))
print(greet("Ada", "Good morning"))

Salida:

[1] "Hello, Ada"
[1] "Good morning, Ada"
challenge icon

Desafío

Fácil

Los precios de envío dependen del artículo y de la zona. Las clases se declaran en Item.R (Letter, Box, cada una con un slot kg) y en Zone.R (Domestic, Abroad, cada una con un slot name). En Rates.R, crea el genérico shipping(item, zone) y un método por cada par:

  • Letter en casa: 1; en el extranjero: 3.
  • Box en casa: 5 más 2 por kg; en el extranjero: 12 más 4 por kg.
  • Cualquier otro par: detén la ejecución con no rate for this item and zone (usa call. = FALSE).

El código proporcionado lee líneas box home 2.5 (artículo, zona, kg), donde las palabras desconocidas permanecen como texto sin formato, e imprime box to home: 10.00 o error: y el mensaje.

Tu código va en Item.R, Zone.R y Rates.R. main.R contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

source("Item.R")
source("Zone.R")
source("Rates.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]]
  kg <- as.numeric(p[3])
  item <- switch(p[1], letter = new("Letter", kg = kg), box = new("Box", kg = kg), kg)
  zone <- switch(p[2], home = new("Domestic", name = "home"), abroad = new("Abroad", name = "abroad"), p[2])
  out <- tryCatch(sprintf("%s to %s: %.2f", p[1], p[2], shipping(item, zone)),
                  error = function(e) paste("error:", conditionMessage(e)))
  cat(out, "\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