בחירת מתודה לפי שני ארגומנטים
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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"אתגר
קלמחירי המשלוח תלויים בפריט ובאזור. המחלקות מוגדרות ב־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 = "")
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורות3ירושה ב-S3
וקטורי מחלקהסדר חיפוש המתודותהרחבה באמצעות NextMethodבדיקה באמצעות inherits()סיכום – שכר העובדים6S4: גנריות ומתודות
יצירת גנריותמתודות עבור רכיבים מובניםבחירת מתודה לפי שני ארגומנטיםsetValidity ו-validObjectסיכום – כסף ומטבעתרגלו בעצמכם: קומפיילר R אונליין