Menu
Coddy logo textTech

callNextMethod

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

בתוך מתודה של S4, callNextMethod() קוראת למתודה של מחלקת האב עם אותם הארגומנטים ומחזירה את התוצאה שלה. מתודת צאצא מתבססת על התשובה של מחלקת האב במקום לחזור עליה:

setClass("Employee", slots = c(name = "character", salary = "numeric"))
setClass("Manager", contains = "Employee", slots = c(reports = "numeric"))
invisible(setGeneric("describe", function(x) standardGeneric("describe")))
setMethod("describe", "Employee", function(x) paste(x@name, "earns", x@salary))
setMethod("describe", "Manager", function(x) paste(callNextMethod(), "and manages", x@reports))
print(describe(new("Manager", name = "Ada", salary = 60000, reports = 4)))

פלט:

[1] "Ada earns 60000 and manages 4"

זה עובד גם עבור show(): הילד מדפיס את השורות של ההורה ואז את השורות שלו:

setClass("Employee", slots = c(name = "character"))
setClass("Manager", contains = "Employee", slots = c(reports = "numeric"))
setMethod("show", "Employee", function(object) cat("Employee:", object@name, "\n"))
setMethod("show", "Manager", function(object) {
  callNextMethod()
  cat("Reports:", object@reports, "\n")
})
new("Manager", name = "Ada", reports = 4)

פלט:

Employee: Ada 
Reports: 4 

new() קוראת ל־initialize() הגנרית. מתודה עבורה יכולה למלא חריצים שהערכים שלהם מחושבים מתוך אחרים. היא קוראת קודם ל־callNextMethod(.Object, ...), ולכן ההגדרה הרגילה ובדיקת התקינות עדיין מתבצעות:

setClass("Order", slots = c(prices = "numeric", total = "numeric"))
setMethod("initialize", "Order", function(.Object, ...) {
  .Object <- callNextMethod(.Object, ...)
  .Object@total <- sum(.Object@prices)
  .Object
})
o <- new("Order", prices = c(2.5, 4, 1))
print(o@total)

פלט:

[1] 7.5

בדומה ל־NextMethod() ב־S3, callNextMethod() מתקדם בשרשרת דרך כמה רמות, כשכל מחלקה מוסיפה את החלק שלה:

setClass("Ticket", slots = c(base = "numeric"))
setClass("Vip", contains = "Ticket")
setClass("Backstage", contains = "Vip")
invisible(setGeneric("price", function(t) standardGeneric("price")))
setMethod("price", "Ticket", function(t) t@base)
setMethod("price", "Vip", function(t) callNextMethod() * 2)
setMethod("price", "Backstage", function(t) callNextMethod() + 50)
cat(price(new("Ticket", base = 30)), price(new("Vip", base = 30)), price(new("Backstage", base = 30)))

פלט:

30 60 110
challenge icon

אתגר

קל

הכרטיסים מגיעים בשלוש רמות, כל אחת בקובץ משלה. המחלקות והגנרית price() מוגדרות. הוסיפו את המתודות:

  • Ticket.R: ‏price() הוא המחיר הבסיסי; ‏show() מדפיסה Ticket for gala ושורה חדשה.
  • Vip.R: ‏price() הוא פי 1.5 ממחיר הכרטיס; ‏show() מדפיסה את שורת הכרטיס ואז את VIP lounge access.
  • Backstage.R: ‏price() הוא מחיר ה־VIP בתוספת 50; ‏show() מדפיסה את שורות ה־VIP ואז את Backstage pass.

השתמשו ב־callNextMethod() במתודות של מחלקות המשנה. הקוד שסופק קורא שורות vip gala 80 (רמה, אירוע, מחיר בסיסי) ומדפיס כל כרטיס ואת מחירו.

הקוד שלכם ייכנס לקבצים Ticket.R,‏ Vip.R ו־Backstage.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.

נסו בעצמכם

source("Ticket.R")
source("Vip.R")
source("Backstage.R")

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  base <- as.numeric(p[3])
  t <- switch(p[1],
    standard = new("Ticket", event = p[2], base = base),
    vip = new("VipTicket", event = p[2], base = base),
    backstage = new("BackstageTicket", event = p[2], base = base))
  print(t)
  cat(sprintf("price: %.2f", price(t)), "\n", sep = "")
}
quiz iconבחנו את עצמכם

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

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

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