Menu
Coddy logo textTech

Wektory klas

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

Dziedziczenie S3 wynika z wektora klas. Obiekt z class = c("manager", "employee") jest menedżerem, a także pracownikiem. Gdy dla funkcji generycznej nie ma metody dla manager, wyszukiwanie metody jest kontynuowane i używana jest metoda 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))

Wynik:

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

Ręczne wpisywanie wektora klas w każdym konstruktorze powiela szczegóły klasy nadrzędnej. Zamiast tego konstruktor klasy nadrzędnej przyjmuje argument class i umieszcza go przed własną klasą, a konstruktor klasy potomnej wywołuje konstruktor klasy nadrzędnej:

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

Wynik:

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

... konstruktora klasy nadrzędnej zbiera dodatkowe pola klasy potomnej, w tym przypadku reports, i umieszcza je za własnymi polami klasy nadrzędnej. Zwykły pracownik nie ma w ogóle pola 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))

Wynik:

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

Kolejność klas w wektorze ma znaczenie: najpierw umieszcza się najbardziej szczegółową klasę. Jeśli najpierw umieścisz klasę nadrzędną, jej metody mają pierwszeństwo, a metody klasy podrzędnej nigdy nie są używane:

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

Wynik:

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

Wyzwanie

Łatwy

Pracownicy i menedżerowie są podzieleni między dwa pliki. Uzupełnij new_employee(name, salary, ..., class = character()) w pliku Employee.R: funkcja zwraca listę zawierającą name, salary oraz dodatkowe pola z ..., z wektorem klas c(class, "employee"). Następnie uzupełnij new_manager(name, salary, reports) w pliku Manager.R. Funkcja ta wywołuje new_employee() z dodatkowym polem reports i klasą manager.

Funkcja label() i jej metoda dla klasy employee są już podane, dzięki czemu menedżerowie otrzymują etykietę bez własnej metody. Dostarczony kod odczytuje wiersze employee Bo 40000 lub manager Ada 60000 4 i wypisuje wektor klas, nazwy pól oraz etykietę.

Umieść swój kod w plikach Employee.R i Manager.R. Plik main.R zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

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

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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 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