Menu
CoddyTech

setValidity dan validObject

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan R di Coddy. Pelajaran 30 dari 57.

setValidity("Class", function(object) ...) menambahkan aturan validitas setelah class dideklarasikan, sehingga pemanggilan setClass() yang panjang tetap singkat. Seperti setGeneric(), fungsi ini mengembalikan nilai yang dicetak di tingkat teratas, jadi bungkus dengan 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)

Output:

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

Perubahan harus dilakukan melalui method yang memeriksa hasilnya. Method withdraw() mengubah slot, memanggil validObject(), dan mengembalikan object hanya jika masih valid:

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)

Output:

refused 30

Sepasang accessor dapat dibuat dari generic: balance(x) membaca dan generic pengganti "balance<-" menulis. Method-nya memeriksa object, jadi balance(a) <- -5 ditolak seperti perubahan buruk lainnya:

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)

Output:

25 refused

validObject(x, test = TRUE) tidak berhenti. Fungsi ini mengembalikan TRUE untuk object yang valid, atau teks masalahnya, yang berguna untuk laporan:

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

Output:

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

Tantangan

Mudah

class Account di Account.R memiliki slot owner dan balance. Lengkapi file ini:

  • tambahkan aturan dengan setValidity() (dibungkus dalam invisible()) yang mengembalikan owner must not be empty atau balance must not be negative;
  • buat generic deposit(acc, amount) dan withdraw(acc, amount) beserta method Account-nya: deposit menghentikan proses dengan amount must be positive (gunakan call. = FALSE) untuk jumlah 0 atau kurang; keduanya mengubah saldo, memanggil validObject(), lalu mengembalikan akun;
  • tambahkan method show() yang mencetak ada: 50 dan baris baru.

Kode yang disediakan membaca pemilik, lalu baris dep 50 atau wd 20, dan mencetak akun setelah setiap perubahan atau refused: beserta masalahnya.

Tulis kodemu di Account.R. main.R berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

source("Account.R")

# Kode input/output yang disediakan: biarkan apa adanya
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 iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler R online