Menu
Coddy logo textTech

Estendendo com NextMethod

Parte da seção Programação Orientada a Objetos do Journey de R da Coddy. Lição 14 de 57.

Um método filho geralmente faz o trabalho do pai e mais um pouco. NextMethod() chama o método pai, então o filho adiciona apenas o que é novo. O pagamento mensal de um gerente é o pagamento de um funcionário mais o bônus:

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

Saída:

3000 6000

NextMethod() continua funcionando por vários níveis. Cada método adiciona sua parte e passa para a classe seguinte à sua:

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

Saída:

[1] 12500

Um método filho também pode verificar primeiro e encaminhar apenas quando a verificação for aprovada. O método do pai retorna o objeto alterado com seu vetor de classes completo, portanto o resultado ainda é uma conta poupança:

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

Saída:

800 savings account

Construtores e métodos reutilizam o pai da mesma forma: new_manager() chama new_employee(), e pay.manager() chama NextMethod(). O código de funcionário é escrito uma vez, e cada subclasse se baseia nele:

new_manager <- function(name, salary, bonus) {
  new_employee(name, salary, bonus = bonus, class = "manager")   # reutiliza o construtor
}
pay.manager <- function(x) NextMethod() + x$bonus / 12            # reutiliza o método
challenge icon

Desafio

Fácil

Contas e contas de poupança estão em dois arquivos. Em Account.R, complete withdraw.account(acc, amount), que interrompe com insufficient funds quando o valor está acima do saldo e, caso contrário, retorna a conta com o saldo reduzido, e format.account(), que retorna ada: 800. Em Savings.R, complete withdraw.savings(), que interrompe com savings limit is 500 para valores acima de 500 e, caso contrário, passa adiante com NextMethod(), e format.savings(), que retorna ada: 800 (savings) chamando NextMethod().

Use call. = FALSE. O genérico e os construtores são fornecidos. O código fornecido lê savings ada 1000 ou account bo 300, depois os valores a serem retirados; ele imprime withdrew 200 ou refused: e a mensagem e, por fim, a conta formatada.

Seu código deve ficar em Account.R e Savings.R. main.R contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

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

# Código de entrada/saída fornecido: mantenha-o como está
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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de R online