Menu
CoddyTech

Cơ bản về NextMethod

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

Bên trong một phương thức, NextMethod() gọi phương thức tiếp theo cho cùng một generic, với cùng các đối số. Với một đối tượng chỉ có một lớp, phương thức tiếp theo là phương thức mặc định, nên một phương thức có thể dùng lại câu trả lời tổng quát rồi bổ sung thêm:

describe <- function(x) UseMethod("describe")
describe.default <- function(x) paste("an object with", length(x), "fields")
describe.task <- function(x) paste0(NextMethod(), ", titled ", x$title)
t <- structure(list(title = "Buy milk", done = FALSE), class = "task")
print(describe(t))

Đầu ra:

[1] "an object with 2 fields, titled Buy milk"

Một đối tượng có thể có nhiều lớp trong một vector, chẳng hạn như c("urgent", "task"). Cơ chế điều phối thử lần lượt từng lớp, còn NextMethod() trong phương thức đầu tiên sẽ chuyển sang phương thức dành cho lớp tiếp theo:

describe <- function(x) UseMethod("describe")
describe.task <- function(x) paste("task:", x$title)
describe.urgent <- function(x) paste("URGENT", NextMethod())
fix <- structure(list(title = "Fix the leak"), class = c("urgent", "task"))
print(describe(fix))

Đầu ra:

[1] "URGENT task: Fix the leak"

NextMethod() chuyển tiếp mọi đối số mà phương thức nhận được, kể cả các đối số bổ sung như sep. Phương thức tiếp theo nhận cùng các giá trị mà bạn không cần liệt kê lại:

label <- function(x, sep = ": ") UseMethod("label")
label.default <- function(x, sep = ": ") paste0("item", sep, x$name)
label.box <- function(x, sep = ": ") paste0("[", NextMethod(), "]")
b <- structure(list(name = "tools"), class = "box")
print(label(b))
print(label(b, sep = " = "))

Đầu ra:

[1] "[item: tools]"
[1] "[item = tools]"

Base R dùng NextMethod() để giữ nguyên lớp khi lấy một phần của vector. Toán tử mặc định [ sẽ bỏ lớp, vì vậy phương thức "[.percent" thực hiện thao tác đó rồi gán lại lớp:

format.percent <- function(x, ...) paste0(unclass(x) * 100, "%")
"[.percent" <- function(x, i) structure(NextMethod(), class = "percent")
p <- structure(c(0.1, 0.25, 0.5), class = "percent")
print(format(p[2:3]))

Đầu ra:

[1] "25%" "50%"
challenge icon

Thử thách

Dễ

Nhiệm vụ và nhiệm vụ khẩn cấp là hai lớp trong hai tệp. Trong Task.R, hãy hoàn thiện hàm generic describe(), phương thức mặc định trả về an item, và describe.task(), hàm trả về an item: Buy milk bằng cách gọi NextMethod() rồi thêm tiêu đề. Trong Urgent.R, hãy hoàn thiện describe.urgent(), hàm trả về URGENT an item: Fix bug bằng cách gọi NextMethod().

Các hàm khởi tạo đã có sẵn: nhiệm vụ khẩn cấp có lớp c("urgent", "task"). Code được cung cấp đọc các dòng task Buy milk, urgent Fix bug hoặc bất kỳ từ nào khác kèm tiêu đề. Mỗi dòng trở thành một đối tượng thuộc lớp tương ứng, rồi chương trình in ra describe() cho từng đối tượng.

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

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  kind <- sub(" .*", "", line)
  title <- sub("^[a-z]+ ", "", line)
  t <- if (kind == "urgent") new_urgent(title) else if (kind == "task") new_task(title) else structure(list(title = title), class = kind)
  cat(describe(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