用 contains 扩展
本课属于 Coddy R 学习旅程的“面向对象编程”单元。第 32 课,共 57 课。
contains = "Animal" 会让新的 S4 类成为 Animal 的子类。子类拥有父类的所有槽,以及自己的槽,而 new() 会接收所有这些槽:
setClass("Animal", slots = c(name = "character", age = "numeric"))
setClass("Dog", contains = "Animal", slots = c(breed = "character"))
rex <- new("Dog", name = "Rex", age = 3, breed = "collie")
print(slotNames("Dog"))
cat(rex@name, rex@breed)输出:
[1] "breed" "name" "age"
Rex collie为父类编写的方法对子类也适用。如果泛型没有针对 Dog 的方法,S4 就会使用针对 Animal 的方法:
setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
invisible(setGeneric("intro", function(a) standardGeneric("intro")))
setMethod("intro", "Animal", function(a) paste("I am", a@name))
print(intro(new("Dog", name = "Rex")))输出:
[1] "I am Rex"子类可以为同一个泛型定义自己的方法,从而重写父类的方法。最具体的类会胜出,其他子类则保留父类的方法:
setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
setClass("Cat", contains = "Animal")
invisible(setGeneric("sound", function(a) standardGeneric("sound")))
setMethod("sound", "Animal", function(a) "...")
setMethod("sound", "Dog", function(a) "woof")
cat(sound(new("Dog", name = "Rex")), sound(new("Cat", name = "Tom")))输出:
woof ...对于狗来说,is(x, "Animal") 的结果是 TRUE,而声明为 "Animal" 的槽位可以接受 Dog。为父类编写的代码适用于每个子类:
setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
setClass("Owner", slots = c(pet = "Animal"))
rex <- new("Dog", name = "Rex")
o <- new("Owner", pet = rex)
cat(is(rex, "Animal"), is(o@pet, "Dog"))输出:
TRUE TRUE挑战
简单员工和经理是两个文件中的 S4 类。Employee.R 声明了 Employee(槽位 name、salary)和泛型 describe(),还需要为 Employee 编写一个方法,使其返回 Bo earns 40000。在 Manager.R 中声明 Manager,它包含 Employee 并添加槽位 reports(数值型),然后重写 describe(),使其返回 Ada earns 60000 and manages 4。
提供的代码会读取 employee Bo 40000 或 manager Ada 60000 4 这样的行,并打印 describe() 的结果、对象是否为员工,以及对象的槽位。
你的代码写在 Employee.R 和 Manager.R 中。main.R 包含提供的输入/输出代码,不能编辑。
亲手试试
source("Employee.R")
source("Manager.R")
# 已提供的输入输出代码:保持原样。
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
x <- if (p[1] == "manager") {
new("Manager", name = p[2], salary = as.numeric(p[3]), reports = as.numeric(p[4]))
} else {
new("Employee", name = p[2], salary = as.numeric(p[3]))
}
cat(describe(x), "\n", sep = "")
cat("is an employee: ", is(x, "Employee"), ", slots: ", paste(slotNames(x), collapse = ", "), "\n", sep = "")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: R 在线编译器