מחלקות וירטואליות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 34 מתוך 57.
מחלקה וירטואלית מתארת את המשותף למשפחה של מחלקות, ואי אפשר ליצור ממנה אובייקטים משלה. הכריזו עליה באמצעות representation("VIRTUAL"); מחלקות המשנה שלה משתמשות ב־contains כרגיל:
setClass("Shape", representation("VIRTUAL"))
setClass("Circle", contains = "Shape", slots = c(r = "numeric"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
cat(isVirtualClass("Shape"), is(new("Circle", r = 1), "Shape"), "\n")
cat(tryCatch({ new("Shape"); "made" }, error = function(e) "not allowed"), "\n")פלט:
TRUE TRUE
not allowed מתודה עבור מחלקה וירטואלית פועלת עבור כל תת־מחלקה. כאן describe() עבור Shape קוראת ל־area(), שכל תת־מחלקה מממשת, כך שהתיאור נכתב פעם אחת:
setClass("Shape", representation("VIRTUAL"))
setClass("Circle", contains = "Shape", slots = c(r = "numeric"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
invisible(setGeneric("area", function(s) standardGeneric("area")))
invisible(setGeneric("describe", function(s) standardGeneric("describe")))
setMethod("area", "Circle", function(s) pi * s@r^2)
setMethod("area", "Square", function(s) s@side^2)
setMethod("describe", "Shape", function(s) sprintf("%s with area %.2f", class(s), area(s)))
for (s in list(new("Circle", r = 1), new("Square", side = 2))) cat(describe(s), "\n")פלט:
Circle with area 3.14
Square with area 4.00 מחלקה וירטואלית יכולה להצהיר על שדות, שיהיו לכל תת־מחלקה שלה:
setClass("Shape", representation("VIRTUAL", label = "character"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
sq <- new("Square", label = "tile", side = 2)
print(slotNames("Square"))פלט:
[1] "side" "label"setClassUnion() יוצרת מחלקה וירטואלית ממחלקות קיימות. משבצת מסוג זה מקבלת כל אחת מהן, למשל איש קשר שהוא כתובת דוא״ל או מספר טלפון:
setClassUnion("Contact", c("character", "numeric"))
setClass("Friend", slots = c(name = "character", contact = "Contact"))
a <- new("Friend", name = "Ada", contact = "ada@x.org")
b <- new("Friend", name = "Bo", contact = 5550123)
cat(class(a@contact), class(b@contact), "\n")
cat(tryCatch({ new("Friend", name = "Cy", contact = TRUE); "ok" }, error = function(e) "refused"), "\n")פלט:
character numeric
refused אתגר
קלאמצעי התשלום חולקים את המחלקה הווירטואלית Payment (חריץ amount) ואת הגנריות fee() ו-receipt(), כולן ב-Payment.R. השלימו:
- ב-
Payment.R, את המתודהreceipt()עבורPayment:card: 100.00 + 2.00 fee, שנבנית משם המחלקה באותיות קטנות, מ-amountומ-fee(); - ב-
Card.R, את המחלקהCard(שמכילה אתPayment) ואתfee()שלה: 2% מהסכום; - ב-
Cash.R, את המחלקהCashואתfee()שלה: 0.
הקוד שסופק קורא שורות card 100 או cash 20, מדפיס כל קבלה ואת הסכום הכולל שנגבה, ואז בודק ש-Payment היא וירטואלית ושאי אפשר ליצור מופע שלה.
הקוד שלך ייכתב בקבצים Payment.R, Card.R ו-Cash.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
source("Payment.R")
source("Card.R")
source("Cash.R")
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
total <- 0
for (line in input) {
p <- strsplit(line, " ")[[1]]
amount <- as.numeric(p[2])
pay <- switch(p[1], card = new("Card", amount = amount), cash = new("Cash", amount = amount))
cat(receipt(pay), "\n", sep = "")
total <- total + amount + fee(pay)
}
cat(sprintf("charged: %.2f", total), "\n", sep = "")
cat("Payment is virtual: ", isVirtualClass("Payment"), "\n", sep = "")
cat(tryCatch({ new("Payment", amount = 1); "created a Payment" }, error = function(e) "cannot create a Payment"), "\n", sep = "")
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורות7ירושה ב-S4
הרחבה באמצעות containscallNextMethodמחלקות וירטואליותבדיקת טיפוסים באמצעות is()סיכום – שומר גן החיותתרגלו בעצמכם: קומפיילר R אונליין