Menu
Coddy logo textTech

Dispatch für zwei Argumente

Teil des Abschnitts Objektorientierte Programmierung der R-Journey von Coddy. Lektion 29 von 57.

Ein S4-Generikum kann seine Methode anhand der Klassen von mehreren Argumenten auswählen. Die Signatur listet eine Klasse pro Argument auf, sodass jedes Klassenpaar seine eigene Methode haben kann:

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

Ausgabe:

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

Die Klasse "ANY" passt zu jeder Klasse. Eine Methode für signature("ANY", "ANY") ist der Fallback, der ausgeführt wird, wenn kein spezifischeres Paar passt:

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

Ausgabe:

two ships bump / nothing happens / nothing happens

Die Reihenfolge der Argumente ist wichtig: signature("A", "B") und signature("B", "A") sind unterschiedliche Methoden. Auch Basisklassen wie numeric und character können in einer Signatur erscheinen:

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

Ausgabe:

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

Die Klasse "missing" in einer Signatur entspricht einem Argument, das überhaupt nicht angegeben wurde, sodass ein generisches Element eine kurze und eine lange Form anbieten kann:

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

Ausgabe:

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

Aufgabe

Einfach

Die Versandpreise hängen vom Artikel und der Zone ab. Die Klassen werden in Item.R (Letter, Box, jeweils mit einem Slot kg) und Zone.R (Domestic, Abroad, jeweils mit einem Slot name) deklariert. Erstelle in Rates.R das Generikum shipping(item, zone) und eine Methode für jedes Paar:

  • Letter zu Hause: 1; ins Ausland: 3.
  • Box zu Hause: 5 plus 2 pro kg; ins Ausland: 12 plus 4 pro kg.
  • Jedes andere Paar: Mit no rate for this item and zone abbrechen (verwende call. = FALSE).

Der bereitgestellte Code liest Zeilen wie box home 2.5 (Artikel, Zone, kg), wobei unbekannte Wörter als normaler Text erhalten bleiben, und gibt box to home: 10.00 oder error: und die Meldung aus.

Dein Code gehört in Item.R, Zone.R und Rates.R. main.R enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

source("Item.R")
source("Zone.R")
source("Rates.R")

# Bereitgestellter Ein-/Ausgabecode: belasse ihn wie er ist
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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-R-Compiler