Menu
Coddy logo textTech

בחירת מתודה לפי שני ארגומנטים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 29 מתוך 57.

גנריקה של S4 יכולה לבחור את המתודה לפי המחלקות של כמה ארגומנטים. החתימה מפרטת מחלקה אחת לכל ארגומנט, ולכן לכל זוג מחלקות יכולה להיות מתודה משלו:

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

פלט:

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

המחלקה "ANY" מתאימה לכל מחלקה. מתודה עבור signature("ANY", "ANY") היא ברירת המחדל שפועלת כשאין זוג ספציפי יותר שמתאים:

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

פלט:

two ships bump / nothing happens / nothing happens

סדר הארגומנטים חשוב: signature("A", "B") ו-signature("B", "A") הן מתודות שונות. גם מחלקות בסיסיות כמו numeric ו-character יכולות להופיע בחתימה:

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

פלט:

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

המחלקה "missing" בחתימה מתאימה לארגומנט שלא הועבר כלל, כך שגנרית אחת יכולה להציע צורה קצרה וצורה ארוכה:

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

פלט:

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

אתגר

קל

מחירי המשלוח תלויים בפריט ובאזור. המחלקות מוגדרות ב־Item.R (Letter, Box, ולכל אחת חריץ kg) וב־Zone.R (Domestic, Abroad, ולכל אחת חריץ name). ב־Rates.R יש ליצור את הגנרית shipping(item, zone) ומתודה אחת לכל זוג:

  • Letter בתוך המדינה: 1; בחו״ל: 3.
  • Box בתוך המדינה: 5 ועוד 2 לכל ק״ג; בחו״ל: 12 ועוד 4 לכל ק״ג.
  • כל זוג אחר: לעצור עם no rate for this item and zone (יש להשתמש ב־call. = FALSE).

הקוד שסופק קורא שורות כגון box home 2.5 (פריט, אזור, ק״ג), כאשר מילים לא מוכרות נשארות טקסט רגיל, ומדפיס box to home: 10.00 או error: ואת הודעת השגיאה.

יש לכתוב את הקוד שלך ב־Item.R, ב־Zone.R וב־Rates.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק ואסור לערוך אותו.

נסו בעצמכם

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

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
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 iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר R אונליין