setValidity và validObject
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 30 trên 57.
setValidity("Class", function(object) ...) thêm quy tắc hợp lệ sau khi khai báo lớp, giúp lời gọi setClass() dài gọn hơn. Giống như setGeneric(), hàm này trả về một giá trị được in ở cấp cao nhất, vì vậy hãy bọc nó trong invisible():
setClass("Account", slots = c(owner = "character", balance = "numeric"))
invisible(setValidity("Account", function(object) {
if (object@balance < 0) return("balance must not be negative")
TRUE
}))
msg <- tryCatch(new("Account", owner = "Ada", balance = -1), error = function(e) conditionMessage(e))
cat(msg)Đầu ra:
invalid class “Account” object: balance must not be negativeCác thay đổi nên được thực hiện thông qua những phương thức kiểm tra kết quả. Phương thức withdraw() thay đổi giá trị trong slot, gọi validObject() và chỉ trả về đối tượng khi đối tượng đó vẫn hợp lệ:
setClass("Account", slots = c(balance = "numeric"))
invisible(setValidity("Account", function(object) {
if (object@balance < 0) "balance must not be negative" else TRUE
}))
invisible(setGeneric("withdraw", function(acc, amount) standardGeneric("withdraw")))
setMethod("withdraw", "Account", function(acc, amount) {
acc@balance <- acc@balance - amount
validObject(acc)
acc
})
a <- new("Account", balance = 50)
a <- withdraw(a, 20)
msg <- tryCatch({ a <- withdraw(a, 100); "done" }, error = function(e) "refused")
cat(msg, a@balance)Đầu ra:
refused 30Một cặp phương thức truy cập có thể dùng generic: balance(x) đọc giá trị, còn generic thay thế "balance<-" ghi giá trị. Phương thức này kiểm tra đối tượng, nên balance(a) <- -5 bị từ chối như mọi thay đổi không hợp lệ khác:
setClass("Account", slots = c(balance = "numeric"),
validity = function(object) if (object@balance < 0) "balance must not be negative" else TRUE)
invisible(setGeneric("balance", function(x) standardGeneric("balance")))
invisible(setGeneric("balance<-", function(x, value) standardGeneric("balance<-")))
setMethod("balance", "Account", function(x) x@balance)
setMethod("balance<-", "Account", function(x, value) {
x@balance <- value
validObject(x)
x
})
a <- new("Account", balance = 10)
balance(a) <- 25
msg <- tryCatch({ balance(a) <- -5; "changed" }, error = function(e) "refused")
cat(balance(a), msg)Đầu ra:
25 refusedvalidObject(x, test = TRUE) không dừng lại. Hàm trả về TRUE nếu đối tượng hợp lệ, hoặc nội dung mô tả vấn đề, rất hữu ích khi tạo báo cáo:
setClass("Box", slots = c(w = "numeric"),
validity = function(object) if (object@w <= 0) "w must be positive" else TRUE)
b <- new("Box", w = 2)
print(validObject(b, test = TRUE))
b@w <- 0
print(validObject(b, test = TRUE))Đầu ra:
[1] TRUE
[1] "w must be positive"Thử thách
DễLớp Account trong Account.R có các khe owner và balance. Hoàn thiện tệp:
- thêm một quy tắc bằng
setValidity()(bọc tronginvisible()) trả vềowner must not be emptyhoặcbalance must not be negative; - tạo các hàm generic
deposit(acc, amount)vàwithdraw(acc, amount)cùng các phương thứcAccounttương ứng:depositdừng vớiamount must be positive(dùngcall. = FALSE) nếu số tiền bằng 0 hoặc nhỏ hơn; cả hai đều thay đổi số dư, gọivalidObject()và trả về tài khoản; - thêm phương thức
show()để in raada: 50và một dòng mới.
Code được cung cấp đọc tên chủ tài khoản, sau đó đọc các dòng dep 50 hoặc wd 20, rồi in tài khoản sau mỗi lần thay đổi hoặc in refused: cùng với vấn đề.
Code của bạn nằm trong Account.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")
# Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyên như hiện tại
input <- suppressWarnings(readLines(file("stdin")))
acc <- tryCatch(new("Account", owner = input[1], balance = 0),
error = function(e) { cat("error: ", sub(".*object: ", "", conditionMessage(e)), "\n", sep = ""); NULL })
if (!is.null(acc)) {
for (line in input[-1]) {
p <- strsplit(line, " ")[[1]]
amount <- as.numeric(p[2])
acc <- tryCatch({
changed <- if (p[1] == "dep") deposit(acc, amount) else withdraw(acc, amount)
print(changed)
changed
}, error = function(e) {
cat("refused: ", sub(".*object: ", "", conditionMessage(e)), "\n", sep = "")
acc
})
}
}
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ẩm3S3 Tính kế thừa
Vector lớpThứ tự tra cứu phương thứcMở rộng với NextMethodKiểm tra với inherits()Ôn tập, tính lương nhân viên6S4 Generics và phương thức
Tạo GenericsPhương thức cho kiểu dựng sẵnĐiều phối theo hai đối sốsetValidity và validObjectÔn tập: tiền và tiền tệTự luyện tập: Trình biên dịch R online