Menu
CoddyTech

Vector lớp

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

Tính kế thừa trong S3 dựa trên vector lớp. Một đối tượng có class = c("manager", "employee") vừa là manager vừa là employee. Khi một hàm tổng quát không có phương thức cho manager, cơ chế điều phối tiếp tục tìm và dùng phương thức employee:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
m <- structure(list(name = "Ada", salary = 60000), class = c("manager", "employee"))
print(class(m))
print(pay(m))

Đầu ra:

[1] "manager"  "employee"
[1] 5000

Viết thủ công vectơ lớp trong mỗi hàm khởi tạo sẽ lặp lại các chi tiết của lớp cha. Thay vào đó, hàm khởi tạo của lớp cha nhận một đối số class và đặt nó trước lớp của chính nó, còn hàm khởi tạo của lớp con gọi hàm khởi tạo của lớp cha:

new_employee <- function(name, salary, ..., class = character()) {
  structure(list(name = name, salary = salary, ...), class = c(class, "employee"))
}
new_manager <- function(name, salary, reports) {
  new_employee(name, salary, reports = reports, class = "manager")
}
m <- new_manager("Ada", 60000, 4)
print(class(m))
print(names(m))

Đầu ra:

[1] "manager"  "employee"
[1] "name"    "salary"  "reports"

Phần ... trong hàm khởi tạo của lớp cha thu thập các trường bổ sung của lớp con, ở đây là reports, rồi đặt chúng sau các trường riêng của lớp cha. Một nhân viên thông thường hoàn toàn không có trường reports:

new_employee <- function(name, salary, ..., class = character()) {
  structure(list(name = name, salary = salary, ...), class = c(class, "employee"))
}
e <- new_employee("Bo", 40000)
print(class(e))
print(names(e))

Đầu ra:

[1] "employee"
[1] "name"   "salary"

Thứ tự của vector lớp rất quan trọng: lớp cụ thể nhất phải đứng đầu. Nếu lớp cha đứng đầu, các phương thức của lớp cha sẽ được ưu tiên và các phương thức của lớp con sẽ không bao giờ được dùng:

title <- function(x) UseMethod("title")
title.employee <- function(x) "employee"
title.manager <- function(x) "manager"
right <- structure(list(), class = c("manager", "employee"))
wrong <- structure(list(), class = c("employee", "manager"))
print(title(right))
print(title(wrong))

Đầu ra:

[1] "manager"
[1] "employee"
challenge icon

Thử thách

Dễ

Nhân viên và quản lý được chia thành hai tệp. Hãy hoàn thiện new_employee(name, salary, ..., class = character()) trong Employee.R: hàm này trả về một danh sách có name, salary và mọi trường bổ sung từ ..., cùng với vectơ lớp c(class, "employee"). Sau đó, hãy hoàn thiện new_manager(name, salary, reports) trong Manager.R. Hàm này gọi new_employee() với trường bổ sung reports và lớp manager.

label() và phương thức employee của hàm này đã được cung cấp, nên quản lý sẽ có nhãn mà không cần phương thức riêng. Code được cung cấp đọc các dòng employee Bo 40000 hoặc manager Ada 60000 4 rồi in ra vectơ lớp, tên các trường và nhãn.

Code của bạn nằm trong Employee.R và Manager.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("Employee.R")
source("Manager.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]]
  x <- if (p[1] == "manager") new_manager(p[2], as.numeric(p[3]), as.numeric(p[4])) else new_employee(p[2], as.numeric(p[3]))
  cat("class: ", paste(class(x), collapse = ", "), "\n", sep = "")
  cat("fields: ", paste(names(x), collapse = ", "), "\n", sep = "")
  cat(label(x), "\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