Menu
CoddyTech

Lớp ảo

Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 34 trên 57.

Lớp ảo mô tả những điểm chung của một nhóm lớp và không thể có đối tượng riêng. Khai báo lớp bằng representation("VIRTUAL"); các lớp con dùng contains như bình thường:

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

Đầu ra:

TRUE TRUE 
not allowed 

Một phương thức dành cho lớp ảo hoạt động với mọi lớp con. Ở đây, describe() của Shape gọi area(), mà mỗi lớp con đều triển khai, nên phần mô tả chỉ cần viết một lần:

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

Đầu ra:

Circle with area 3.14 
Square with area 4.00 

Một lớp ảo có thể khai báo các thuộc tính, mà mọi lớp con đều có:

setClass("Shape", representation("VIRTUAL", label = "character"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
sq <- new("Square", label = "tile", side = 2)
print(slotNames("Square"))

Đầu ra:

[1] "side"  "label"

setClassUnion() tạo một lớp ảo từ các lớp có sẵn. Một slot thuộc kiểu đó chấp nhận bất kỳ lớp nào trong số đó, chẳng hạn như thông tin liên hệ có thể là địa chỉ email hoặc số điện thoại:

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

Đầu ra:

character numeric 
refused 
challenge icon

Thử thách

Dễ

Các khoản thanh toán dùng chung lớp ảo (class) Payment (slot amount) và các hàm generic fee() cùng receipt(), tất cả đều nằm trong Payment.R. Hãy hoàn thành:

  • trong Payment.R, phương thức receipt() cho Payment: card: 100.00 + 2.00 fee, được tạo từ tên lớp viết thường, amount và fee();
  • trong Card.R, lớp Card (chứa Payment) và fee() của lớp này: 2% số tiền;
  • trong Cash.R, lớp Cash và fee() của lớp này: 0.

Code được cung cấp đọc các dòng card 100 hoặc cash 20, in từng biên lai và tổng số tiền đã thu, sau đó kiểm tra rằng Payment là lớp ảo và không thể khởi tạo.

Hãy viết code trong Payment.R, Card.R và Cash.R. main.R chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

source("Payment.R")
source("Card.R")
source("Cash.R")

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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 = "")
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch R online