Menu
Coddy logo textTech

setValidity ve validObject

Coddy'nin R Journey'sinin Nesne Tabanlı Programlama bölümünün bir parçası. Ders 30 / 57.

setValidity("Class", function(object) ...), sınıf bildirildikten sonra geçerlilik kuralını ekler; bu da uzun bir setClass() çağrısını kısa tutar. setGeneric() gibi, en üst düzeyde yazdırılan bir değer döndürür; bu nedenle onu invisible() içine sarın:

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)

Çıktı:

invalid class “Account” object: balance must not be negative

Değişiklikler, sonucu denetleyen yöntemler aracılığıyla yapılmalıdır. Bir withdraw() yöntemi slot'u değiştirir, validObject() çağrısını yapar ve nesneyi yalnızca hâlâ geçerliyse döndürür:

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)

Çıktı:

refused 30

Bir erişimci çifti generiklerden oluşabilir: balance(x) okur ve bir değiştirme generiği olan "balance<-" yazar. Yöntemi nesneyi denetlediğinden, balance(a) <- -5 diğer tüm hatalı değişiklikler gibi reddedilir:

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)

Çıktı:

25 refused

validObject(x, test = TRUE) durmaz. Geçerli bir nesne için TRUE veya bir rapor için kullanışlı olan sorun metnini döndürür:

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))

Çıktı:

[1] TRUE
[1] "w must be positive"
challenge icon

Görev

Kolay

Account.R içindeki Account sınıfı owner ve balance yuvalarına sahiptir. Dosyayı tamamlayın:

  • setValidity() ile ( invisible() içine sarılmış) owner must not be empty veya balance must not be negative döndüren bir kural ekleyin;
  • deposit(acc, amount) ve withdraw(acc, amount) generic'lerini ve bunların Account metotlarını oluşturun: deposit, 0 veya daha küçük miktarlar için amount must be positive hatasıyla durmalıdır (call. = FALSE kullanın); her ikisi de bakiyeyi değiştirmeli, validObject() çağırmalı ve hesabı döndürmelidir;
  • ada: 50 yazdıran ve yeni satıra geçen bir show() metodu ekleyin.

Sağlanan kod, hesabın sahibini ve ardından dep 50 veya wd 20 biçimindeki satırları okur; her değişiklikten sonra hesabı, aksi durumda refused: ifadesini ve sorunu yazdırır.

Kodunuz Account.R dosyasına yazılmalıdır. main.R, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

source("Account.R")

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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
    })
  }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Tabanlı Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online R derleyicisi