Menu
Coddy logo textTech

Kalıtım ve callSuper

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

contains = "Account", bir Referans Sınıfının Account sınıfındaki her alanı ve yöntemi devralmasını sağlar. Alt sınıf kendi alanlarını ve yöntemlerini ekler:

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

Çıktı:

210 TRUE

Bir alt sınıf, aynı ada sahip bir yöntem tanımlayarak bir yöntemi geçersiz kılar. İçinde callSuper(...), üst sınıfın sürümünü çağırır; böylece alt sınıf yalnızca yeni olanı ekler:

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

Çıktı:

limit is 500 
insufficient funds 
100 

initialize diğer tüm metotlar gibi miras alınır ve geçersiz kılınır. Alt sınıfın initialize metodu, üst sınıfın alanlarını ayarlamasına izin vermek için callSuper(...) çağrısını yapar, ardından kendi varsayılanlarını ayarlar:

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)

Çıktı:

Bo 0 0.01

Farklı alt sınıflara ait nesneler aynı yöntem çağrısına kendi şekillerinde yanıt verir; bu nedenle karışık bir liste üzerinde yapılan bir döngünün sınıf kontrollerine ihtiyacı yoktur:

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

Çıktı:

98 101
challenge icon

Görev

Kolay

Hesaplar ve tasarruf hesapları, iki dosyada bulunan Referans Sınıflarıdır. Metotları tamamlayın:

  • Account, Account.R içinde (alanlar owner, balance): initialize, verilmediğinde bakiyeyi 0 olarak ayarlar; deposit(x); withdraw(x), insufficient funds ile durur; month_end(), 1 ücret alır; describe(), ada: 99 döndürür.
  • Savings, Savings.R içinde (Account içerir, rate alanı): withdraw(x), 500'ün üzerinde limit is 500 ile durur ve aksi takdirde callSuper(x) çağırır; month_end(), ücret yerine faiz olan balance * rate değerini ekler; describe(), callSuper() ile (savings) ekler.

call. = FALSE kullanın. Her iki tanım da suppressMessages() içine sarılır. Sağlanan kod savings ada 0.1 veya account bo okur, ardından dep 100, wd 30 ya da month komutunu işler ve her birinin ardından describe() ya da refused: ile mesajı yazdırır.

Kodunuz Account.R ve Savings.R dosyalarına gider. main.R, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

source("Account.R")
source("Savings.R")

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakı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 = "")
}
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