Menu
Coddy logo textTech

Порядок поиска методов

Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 13 из 57.

При каждом вызове R просматривает вектор классов слева направо и запускает первый найденный метод. Если ни у одного класса нет метода, используется метод по умолчанию. Разные объекты в одной иерархии могут останавливаться на разных уровнях:

move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.default <- function(x) "stays"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
dog <- structure(list(), class = c("dog", "animal"))
rock <- structure(list(), class = "rock")
cat(move(penguin), move(dog), move(rock))

Вывод:

flies walks stays

Дочерний класс переопределяет метод родительского класса, определяя собственный метод. Переопределение влияет только на дочерний класс и всё, что находится ниже него; родительский класс и его другие дочерние классы сохраняют метод родительского класса:

move <- function(x) UseMethod("move")
move.animal <- function(x) "walks"
move.bird <- function(x) "flies"
move.penguin <- function(x) "swims"
penguin <- structure(list(), class = c("penguin", "bird", "animal"))
sparrow <- structure(list(), class = c("bird", "animal"))
cat(move(penguin), move(sparrow))

Результат:

swims flies

Каждый generic ищется независимо. Один объект может получить sound() из собственного класса и move() от родительского класса, а метод родительского класса может снова вызвать другие generic-функции, которые выполняют диспетчеризацию по дочернему классу:

sound <- function(x) UseMethod("sound")
move <- function(x) UseMethod("move")
describe <- function(x) UseMethod("describe")
sound.animal <- function(x) "..."
sound.dog <- function(x) "woof"
move.animal <- function(x) "walks"
describe.animal <- function(x) paste(x$name, "says", sound(x), "and", move(x))
rex <- structure(list(name = "Rex"), class = c("dog", "animal"))
print(describe(rex))

Результат:

[1] "Rex says woof and walks"

Для объекта с атрибутом класса диспетчеризация смотрит только на этот атрибут, а затем — на значение по умолчанию. Сам объект внутри по-прежнему является списком, но метод для list не проверяется:

size <- function(x) UseMethod("size")
size.list <- function(x) "a list"
size.default <- function(x) "default"
bag <- structure(list(1, 2), class = "bag")
cat(size(list(1, 2)), "/", size(bag))

Результат:

a list / default
challenge icon

Задание

Легко

Квадрат — это прямоугольник с равными сторонами. В Rectangle.R напишите методы area.rectangle(), perimeter.rectangle() и name.rectangle(), который возвращает rectangle 2x3. В Square.R завершите new_square(side), который вызывает new_rectangle() с классом square, и переопределите только name() с помощью name.square(), который возвращает square 2. Квадраты должны использовать area() и perimeter() прямоугольника.

Обобщения и new_rectangle() предоставлены. Предоставленный код считывает строки с двумя числами (прямоугольник) или одним числом (квадрат) и выводит square 2: area 4, perimeter 8.

Ваш код должен находиться в Rectangle.R и Square.R. В main.R содержится предоставленный код ввода/вывода, и его нельзя изменять.

Попробуйте сами

source("Rectangle.R")
source("Square.R")

# Предоставленный код ввода/вывода: оставьте его как есть
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  n <- as.numeric(strsplit(line, " ")[[1]])
  s <- if (length(n) == 1) new_square(n[1]) else new_rectangle(n[1], n[2])
  cat(name(s), ": area ", area(s), ", perimeter ", perimeter(s), "\n", sep = "")
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор R