setValidity와 validObject
Coddy R 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 30번째.
setValidity("Class", function(object) ...)는 클래스가 선언된 후 유효성 규칙을 추가하므로, 긴 setClass() 호출을 짧게 유지할 수 있습니다. setGeneric()과 마찬가지로 최상위 수준에서 출력되는 값을 반환하므로 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)출력:
invalid class “Account” object: balance must not be negative변경은 결과를 확인하는 메서드를 통해 이루어져야 합니다. withdraw() 메서드는 슬롯을 변경하고, validObject()를 호출한 다음, 객체가 여전히 유효할 때만 객체를 반환합니다.
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)출력:
refused 30접근자 쌍은 제네릭으로 만들 수 있습니다. balance(x)는 읽고 대체 제네릭 "balance<-"은 씁니다. 해당 메서드는 객체를 검사하므로 balance(a) <- -5와 같은 잘못된 변경은 다른 경우와 마찬가지로 거부됩니다.
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)출력:
25 refusedvalidObject(x, test = TRUE)는 중단하지 않습니다. 유효한 객체이면 TRUE를 반환하고, 그렇지 않으면 문제 텍스트를 반환하므로 보고서에 유용합니다:
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))출력:
[1] TRUE
[1] "w must be positive"챌린지
쉬움Account.R의 Account 클래스에는 owner와 balance 슬롯이 있습니다. 파일을 완성하세요:
setValidity()(invisible()로 감싼 형태)를 사용하여owner must not be empty또는balance must not be negative를 반환하는 규칙을 추가하세요;deposit(acc, amount)와withdraw(acc, amount)제네릭 및 해당Account메서드를 만드세요.deposit은 금액이 0 이하일 때amount must be positive와 함께 중단해야 합니다(call. = FALSE사용). 두 메서드 모두 잔액을 변경하고,validObject()를 호출한 다음 계정을 반환해야 합니다;ada: 50을 출력하고 줄바꿈하는show()메서드를 추가하세요.
제공된 코드는 소유자를 읽은 다음 dep 50 또는 wd 20 형식의 줄을 읽고, 변경할 때마다 계정을 출력하거나 refused: 와 문제 내용을 출력합니다.
코드는 Account.R에 작성하세요. main.R에는 제공된 입력/출력 코드가 들어 있으며 편집할 수 없습니다.
직접 해보기
source("Account.R")
# 제공된 입출력 코드: 그대로 유지하세요
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
})
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 R 컴파일러