Menu
Coddy logo textTech

Vetores de classe

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

A herança S3 vem do vetor de classes. Um objeto com class = c("manager", "employee") é um gerente e também um funcionário. Quando um genérico não tem método para manager, o despacho prossegue e usa o método employee:

pay <- function(x) UseMethod("pay")
pay.employee <- function(x) x$salary / 12
m <- structure(list(name = "Ada", salary = 60000), class = c("manager", "employee"))
print(class(m))
print(pay(m))

Saída:

[1] "manager"  "employee"
[1] 5000

Escrever o vetor de classes manualmente em cada construtor repete os detalhes do pai. Em vez disso, o construtor pai recebe um argumento class e o coloca à frente de sua própria classe, e o construtor filho chama o construtor pai:

new_employee <- function(name, salary, ..., class = character()) {
  structure(list(name = name, salary = salary, ...), class = c(class, "employee"))
}
new_manager <- function(name, salary, reports) {
  new_employee(name, salary, reports = reports, class = "manager")
}
m <- new_manager("Ada", 60000, 4)
print(class(m))
print(names(m))

Saída:

[1] "manager"  "employee"
[1] "name"    "salary"  "reports"

O ... do construtor pai coleta os campos extras do filho, neste caso reports, e os coloca depois dos próprios campos do pai. Um funcionário comum não tem nenhum campo reports:

new_employee <- function(name, salary, ..., class = character()) {
  structure(list(name = name, salary = salary, ...), class = c(class, "employee"))
}
e <- new_employee("Bo", 40000)
print(class(e))
print(names(e))

Saída:

[1] "employee"
[1] "name"   "salary"

A ordem do vetor de classes é importante: a classe mais específica vem primeiro. Com a classe pai primeiro, seus métodos prevalecem e os métodos da classe filha nunca são usados:

title <- function(x) UseMethod("title")
title.employee <- function(x) "employee"
title.manager <- function(x) "manager"
right <- structure(list(), class = c("manager", "employee"))
wrong <- structure(list(), class = c("employee", "manager"))
print(title(right))
print(title(wrong))

Saída:

[1] "manager"
[1] "employee"
challenge icon

Desafio

Fácil

Funcionários e gerentes estão divididos em dois arquivos. Complete new_employee(name, salary, ..., class = character()) em Employee.R: ele retorna uma lista com name, salary e quaisquer campos extras de ..., com o vetor de classes c(class, "employee"). Em seguida, complete new_manager(name, salary, reports) em Manager.R, que chama new_employee() com o campo extra reports e a classe manager.

label() e seu método employee são fornecidos, portanto os gerentes recebem um rótulo sem ter um método próprio. O código fornecido lê linhas employee Bo 40000 ou manager Ada 60000 4 e imprime o vetor de classes, os nomes dos campos e o rótulo.

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

Experimente você mesmo

source("Employee.R")
source("Manager.R")

# Código de entrada/saída fornecido: mantenha-o como está
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  x <- if (p[1] == "manager") new_manager(p[2], as.numeric(p[3]), as.numeric(p[4])) else new_employee(p[2], as.numeric(p[3]))
  cat("class: ", paste(class(x), collapse = ", "), "\n", sep = "")
  cat("fields: ", paste(names(x), collapse = ", "), "\n", sep = "")
  cat(label(x), "\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