Menu
CoddyTech

callNextMethod

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 33 trên 57.

Bên trong một phương thức S4, callNextMethod() gọi phương thức của lớp cha với cùng các đối số và trả về kết quả của phương thức đó. Phương thức lớp con bổ sung dựa trên câu trả lời của lớp cha thay vì lặp lại câu trả lời ấy:

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

Đầu ra:

[1] "Ada earns 60000 and manages 4"

Cách này cũng áp dụng với show(): lớp con in ra các dòng của lớp cha rồi đến các dòng của chính nó:

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)

Đầu ra:

Employee: Ada 
Reports: 4 

new() gọi initialize() tổng quát. Một phương thức cho hàm này có thể điền vào các slot được tính từ những slot khác. Trước tiên, hàm gọi callNextMethod(.Object, ...), nên quá trình thiết lập thông thường và bước kiểm tra tính hợp lệ vẫn diễn ra:

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)

Đầu ra:

[1] 7.5

Giống như NextMethod() trong S3, callNextMethod() lần lượt đi qua nhiều cấp, mỗi lớp bổ sung phần của mình:

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

Đầu ra:

30 60 110
challenge icon

Thử thách

Dễ

Vé có ba cấp độ, mỗi cấp nằm trong một tệp riêng. Các lớp (class) và hàm tổng quát price() đã được khai báo. Hãy thêm các phương thức:

  • Ticket.R: price() là giá vé cơ bản; show() in ra Ticket for gala và một dòng mới.
  • Vip.R: price() bằng 1.5 lần giá vé; show() in ra dòng vé rồi đến VIP lounge access.
  • Backstage.R: price() bằng giá vé VIP cộng thêm 50; show() in ra các dòng VIP rồi đến Backstage pass.

Dùng callNextMethod() trong các phương thức của lớp con. Code được cung cấp đọc các dòng vip gala 80 (cấp độ, sự kiện, giá cơ bản) rồi in ra từng vé và giá vé.

Code của bạn nằm trong Ticket.R, Vip.R và Backstage.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("Ticket.R")
source("Vip.R")
source("Backstage.R")

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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 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