Menu
Coddy logo textTech

Rozszerzanie za pomocą NextMethod

Część sekcji Programowanie obiektowe ścieżki R w Coddy. Lekcja 14 z 57.

Metoda klasy potomnej często wykonuje pracę metody klasy nadrzędnej i dodaje do niej coś jeszcze. NextMethod() wywołuje metodę klasy nadrzędnej, więc klasa potomna dodaje tylko to, co nowe. Miesięczne wynagrodzenie menedżera to wynagrodzenie pracownika powiększone o premię:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
m <- structure(list(salary = 60000, bonus = 12000), class = c("manager", "employee"))
e <- structure(list(salary = 36000), class = "employee")
cat(pay(e), pay(m))

Wynik:

3000 6000

NextMethod() działa dalej przez kilka poziomów. Każda metoda dodaje swoją część i przekazuje działanie klasie następującej po niej:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
pay.manager <- function(x) NextMethod() + x$bonus / 12
pay.director <- function(x) NextMethod() + 500
d <- structure(list(salary = 120000, bonus = 24000),
               class = c("director", "manager", "employee"))
print(pay(d))

Wynik:

[1] 12500

Metoda potomna może również najpierw przeprowadzić kontrolę i przekazać obsługę dalej tylko wtedy, gdy kontrola się powiedzie. Metoda klasy nadrzędnej zwraca zmieniony obiekt z pełnym wektorem klas, więc wynik nadal jest kontem oszczędnościowym:

withdraw <- function(acc, amount) UseMethod("withdraw")
withdraw.account <- function(acc, amount) {
  if (amount > acc$balance) stop("insufficient funds", call. = FALSE)
  acc$balance <- acc$balance - amount
  acc
}
withdraw.savings <- function(acc, amount) {
  if (amount > 500) stop("savings limit is 500", call. = FALSE)
  NextMethod()
}
s <- structure(list(balance = 1000), class = c("savings", "account"))
s <- withdraw(s, 200)
cat(s$balance, class(s))

Wynik:

800 savings account

Konstruktory i metody ponownie wykorzystują klasę nadrzędną w ten sam sposób: new_manager() wywołuje new_employee(), a pay.manager() wywołuje NextMethod(). Kod pracownika zapisuje się raz, a każda podklasa go rozszerza:

new_manager <- function(name, salary, bonus) {
  new_employee(name, salary, bonus = bonus, class = "manager")   # wykorzystaj ponownie konstruktor
}
pay.manager <- function(x) NextMethod() + x$bonus / 12            # wykorzystaj ponownie metodę
challenge icon

Wyzwanie

Łatwy

Konta i konta oszczędnościowe znajdują się w dwóch plikach. W Account.R uzupełnij withdraw.account(acc, amount), która przerywa działanie z komunikatem insufficient funds, gdy kwota przekracza saldo, a w przeciwnym razie zwraca konto z niższym saldem, oraz format.account(), która zwraca ada: 800. W Savings.R uzupełnij withdraw.savings(), która przerywa działanie z komunikatem savings limit is 500 dla kwot powyżej 500, a w przeciwnym razie przekazuje sterowanie dalej za pomocą NextMethod(), oraz format.savings(), która zwraca ada: 800 (savings), wywołując NextMethod().

Użyj call. = FALSE. Funkcja generyczna i konstruktory są już podane. Dostarczony kod odczytuje savings ada 1000 lub account bo 300, a następnie kwoty do wypłaty; wypisuje withdrew 200 albo refused: i komunikat, a na końcu sformatowane konto.

Twój kod umieść w plikach Account.R i Savings.R. main.R zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

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

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
acc <- if (p[1] == "savings") new_savings(p[2], as.numeric(p[3])) else new_account(p[2], as.numeric(p[3]))
for (amount in as.numeric(input[-1])) {
  acc <- tryCatch({
    acc <- withdraw(acc, amount)
    cat("withdrew ", amount, "\n", sep = "")
    acc
  }, error = function(e) {
    cat("refused: ", conditionMessage(e), "\n", sep = "")
    acc
  })
}
cat(format(acc), "\n", sep = "")
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator R online