סדר חיפוש המתודות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 13 מתוך 57.
בכל קריאה, R עובר על וקטור המחלקות משמאל לימין ומפעיל את המתודה הראשונה שהוא מוצא. אם לאף מחלקה אין מתודה, הוא משתמש בברירת המחדל. אובייקטים שונים באותה היררכיה יכולים לעצור ברמות שונות:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.default <- function(x) "stays"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
dog <- structure(list(), class = c("dog", "animal"))
rock <- structure(list(), class = "rock")
cat(move(penguin), move(dog), move(rock))פלט:
flies walks staysמחלקת צאצא דורסת מתודה של מחלקת אב באמצעות הגדרת מתודה משלה. הדריסה משפיעה רק על מחלקת הצאצא ועל כל מה שמתחתיה; מחלקת האב ושאר מחלקות הצאצאים שלה ממשיכות להשתמש במתודה של מחלקת האב:
move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.penguin <- function(x) "swims"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
sparrow <- structure(list(), class = c("bird", "animal"))
cat(move(penguin), move(sparrow))פלט:
swims fliesהחיפוש אחר כל פונקציה גנרית מתבצע בנפרד. אובייקט אחד יכול לקבל את sound() מהמחלקה שלו ואת move() ממחלקת האב, ומתודת אב יכולה לקרוא לפונקציות גנריות אחרות שמבצעות שוב שיגור לפי מחלקת הבן:
sound <- function(x) UseMethod("sound")
move <- function(x) UseMethod("move")
describe <- function(x) UseMethod("describe")
sound.animal <- function(x) "..."
sound.dog <- function(x) "woof"
move.animal <- function(x) "walks"
describe.animal <- function(x) paste(x$name, "says", sound(x), "and", move(x))
rex <- structure(list(name = "Rex"), class = c("dog", "animal"))
print(describe(rex))פלט:
[1] "Rex says woof and walks"עבור אובייקט עם מאפיין מחלקה, מנגנון השליחה בודק רק את המאפיין הזה ואז את ברירת המחדל. האובייקט עדיין רשימה מבפנים, אבל לא מנסים מתודה עבור list:
size <- function(x) UseMethod("size")
size.list <- function(x) "a list"
size.default <- function(x) "default"
bag <- structure(list(1, 2), class = "bag")
cat(size(list(1, 2)), "/", size(bag))פלט:
a list / defaultאתגר
קלריבוע הוא מלבן שצלעותיו שוות. ב־Rectangle.R כתבו את המתודות area.rectangle(), perimeter.rectangle() ו־name.rectangle(), שמחזירה rectangle 2x3. ב־Square.R השלימו את new_square(side), שקוראת ל־new_rectangle() עם המחלקה square, ודרסו רק את name() באמצעות name.square(), שמחזירה square 2. ריבועים חייבים להשתמש ב־area() וב־perimeter() של המלבן.
הגנריות ו־new_rectangle() נתונים. הקוד שסופק קורא שורות עם שני מספרים (מלבן) או מספר אחד (ריבוע) ומדפיס square 2: area 4, perimeter 8.
הקוד שלכם ייכתב ב־Rectangle.R וב־Square.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
source("Rectangle.R")
source("Square.R")
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
n <- as.numeric(strsplit(line, " ")[[1]])
s <- if (length(n) == 1) new_square(n[1]) else new_rectangle(n[1], n[2])
cat(name(s), ": area ", area(s), ", perimeter ", perimeter(s), "\n", sep = "")
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורות3ירושה ב-S3
וקטורי מחלקהסדר חיפוש המתודותהרחבה באמצעות NextMethodבדיקה באמצעות inherits()סיכום – שכר העובדיםתרגלו בעצמכם: קומפיילר R אונליין