Kế thừa và callSuper
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 40 trên 57.
contains = "Account" giúp lớp tham chiếu kế thừa mọi trường và phương thức của Account. Lớp con thêm các trường và phương thức riêng:
Account <- suppressMessages(setRefClass("Account",
fields = list(owner = "character", balance = "numeric"),
methods = list(deposit = function(x) balance <<- balance + x)
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
fields = list(rate = "numeric"),
methods = list(add_interest = function() deposit(balance * rate))
))
s <- Savings$new(owner = "Ada", balance = 100, rate = 0.05)
s$deposit(100)
s$add_interest()
cat(s$balance, is(s, "Account"))Đầu ra:
210 TRUELớp con ghi đè một phương thức bằng cách định nghĩa phương thức cùng tên. Bên trong phương thức đó, callSuper(...) gọi phiên bản của lớp cha, để lớp con chỉ thêm những gì mới:
Account <- suppressMessages(setRefClass("Account",
fields = list(balance = "numeric"),
methods = list(withdraw = function(x) {
if (x > balance) stop("insufficient funds", call. = FALSE)
balance <<- balance - x
})
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
methods = list(withdraw = function(x) {
if (x > 500) stop("limit is 500", call. = FALSE)
callSuper(x)
})
))
s <- Savings$new(balance = 300)
s$withdraw(200)
for (x in c(600, 400)) cat(tryCatch({ s$withdraw(x); "ok" }, error = function(e) conditionMessage(e)), "\n")
cat(s$balance, "\n")Đầu ra:
limit is 500
insufficient funds
100 initialize được kế thừa và ghi đè như mọi phương thức. initialize của lớp con gọi callSuper(...) để lớp cha thiết lập các trường của nó, rồi đặt các giá trị mặc định riêng:
Account <- suppressMessages(setRefClass("Account",
fields = list(owner = "character", balance = "numeric"),
methods = list(initialize = function(...) {
initFields(...)
if (length(balance) == 0) balance <<- 0
invisible(.self)
})
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
fields = list(rate = "numeric"),
methods = list(initialize = function(...) {
callSuper(...)
if (length(rate) == 0) rate <<- 0.01
invisible(.self)
})
))
s <- Savings$new(owner = "Bo")
cat(s$owner, s$balance, s$rate)Đầu ra:
Bo 0 0.01Các đối tượng thuộc những lớp con khác nhau sẽ xử lý cùng một lời gọi phương thức theo cách riêng, vì vậy vòng lặp qua danh sách gồm nhiều kiểu đối tượng không cần kiểm tra lớp:
Account <- suppressMessages(setRefClass("Account",
fields = list(balance = "numeric"),
methods = list(month_end = function() balance <<- balance - 2)
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
methods = list(month_end = function() balance <<- balance * 1.01)
))
bank <- list(Account$new(balance = 100), Savings$new(balance = 100))
for (a in bank) a$month_end()
cat(vapply(bank, function(a) a$balance, numeric(1)))Đầu ra:
98 101Thử thách
DễTài khoản và tài khoản tiết kiệm là các lớp tham chiếu trong hai tệp. Hoàn thiện các phương thức:
AccounttrongAccount.R(các trườngowner,balance):initializeđặt số dư thành 0 nếu không được cung cấp;deposit(x);withdraw(x)dừng vớiinsufficient funds;month_end()thu phí 1;describe()trả vềada: 99.SavingstrongSavings.R(chứaAccount, trườngrate):withdraw(x)dừng vớilimit is 500nếu vượt quá 500, còn không thì gọicallSuper(x);month_end()cộng tiền lãi,balance * rate, thay vì thu phí;describe()thêm(savings)bằngcallSuper().
Dùng call. = FALSE. Cả hai định nghĩa đều được bọc trong suppressMessages(). Code được cung cấp đọc savings ada 0.1 hoặc account bo, sau đó đọc dep 100, wd 30 hoặc month, rồi in ra describe() hoặc refused: cùng thông báo sau mỗi thao tác.
Code của bạn đặt trong Account.R và Savings.R. main.R chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.
Tự làm thử
source("Account.R")
source("Savings.R")
# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
acc <- if (p[1] == "savings") Savings$new(owner = p[2], rate = as.numeric(p[3])) else Account$new(owner = p[2])
for (line in input[-1]) {
q <- strsplit(line, " ")[[1]]
msg <- tryCatch({
if (q[1] == "dep") acc$deposit(as.numeric(q[2]))
if (q[1] == "wd") acc$withdraw(as.numeric(q[2]))
if (q[1] == "month") acc$month_end()
acc$describe()
}, error = function(e) paste("refused:", conditionMessage(e)))
cat(line, ": ", msg, "\n", sep = "")
}
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
1Kiến thức cơ bản về S3
Làm việc với tệpDanh sách với một lớpHàm khởi tạoPhương thức in ra và định dạngTrình xác thực và hàm hỗ trợÔn tập: nhiệt độ4Tính đóng gói trong R
Closure dưới dạng đối tượngMôi trường dưới dạng đối tượngHàm truy cậpBảo vệ trạng tháiÔn tập: đồng hồ tính phí đỗ xe2S3, hàm generic và phương thức
Hàm generic và UseMethodPhương thức mặc địnhPhương thức cho hàm generic cơ sởCơ bản về NextMethodÔn tập: diện tích hình5Các lớp S4
Định nghĩa lớp S4Slot và quyền truy cậpKiểm tra tính hợp lệPhương thức showÔn tập: Danh mục sản phẩm8Lớp tham chiếu
Định nghĩa lớp tham chiếuPhương thức và cập nhật trườngNgữ nghĩa sao chépKế thừa và callSuperÔn tập: hàng đợi tác vụTự luyện tập: Trình biên dịch R online