Виртуальные классы
Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 34 из 57.
Виртуальный класс описывает то, что является общим для семейства классов, и не может иметь собственных объектов. Объявите его с помощью representation("VIRTUAL"); его подклассы используют contains как обычно:
setClass("Shape", representation("VIRTUAL"))
setClass("Circle", contains = "Shape", slots = c(r = "numeric"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
cat(isVirtualClass("Shape"), is(new("Circle", r = 1), "Shape"), "\n")
cat(tryCatch({ new("Shape"); "made" }, error = function(e) "not allowed"), "\n")Вывод:
TRUE TRUE
not allowed Метод для виртуального класса работает для каждого подкласса. Здесь describe() для Shape вызывает area(), который реализует каждый подкласс, поэтому описание записывается один раз:
setClass("Shape", representation("VIRTUAL"))
setClass("Circle", contains = "Shape", slots = c(r = "numeric"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
invisible(setGeneric("area", function(s) standardGeneric("area")))
invisible(setGeneric("describe", function(s) standardGeneric("describe")))
setMethod("area", "Circle", function(s) pi * s@r^2)
setMethod("area", "Square", function(s) s@side^2)
setMethod("describe", "Shape", function(s) sprintf("%s with area %.2f", class(s), area(s)))
for (s in list(new("Circle", r = 1), new("Square", side = 2))) cat(describe(s), "\n")Вывод:
Circle with area 3.14
Square with area 4.00 Виртуальный класс может объявлять слоты, которые затем есть у каждого подкласса:
setClass("Shape", representation("VIRTUAL", label = "character"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
sq <- new("Square", label = "tile", side = 2)
print(slotNames("Square"))Вывод:
[1] "side" "label"setClassUnion() создаёт виртуальный класс из существующих классов. Слот такого типа принимает любой из них, например контакт, который может быть адресом электронной почты или номером телефона:
setClassUnion("Contact", c("character", "numeric"))
setClass("Friend", slots = c(name = "character", contact = "Contact"))
a <- new("Friend", name = "Ada", contact = "ada@x.org")
b <- new("Friend", name = "Bo", contact = 5550123)
cat(class(a@contact), class(b@contact), "\n")
cat(tryCatch({ new("Friend", name = "Cy", contact = TRUE); "ok" }, error = function(e) "refused"), "\n")Результат:
character numeric
refused Задание
ЛегкоПлатежи используют виртуальный класс Payment (слот amount) и обобщённые функции fee() и receipt(), все они находятся в Payment.R. Выполните следующие задания:
- в
Payment.Rреализуйте методreceipt()дляPayment:card: 100.00 + 2.00 fee, сформированный из имени класса в нижнем регистре,amountиfee(); - в
Card.Rсоздайте классCard(содержащийPayment) и егоfee(): 2% от суммы; - в
Cash.Rсоздайте классCashи егоfee(): 0.
Предоставленный код считывает строки card 100 или cash 20, выводит каждый чек и общую списанную сумму, а затем проверяет, что Payment является виртуальным и не может быть создан.
Ваш код должен находиться в Payment.R, Card.R и Cash.R. В main.R находится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
source("Payment.R")
source("Card.R")
source("Cash.R")
# Предоставленный код ввода/вывода: оставьте его как есть
input <- suppressWarnings(readLines(file("stdin")))
total <- 0
for (line in input) {
p <- strsplit(line, " ")[[1]]
amount <- as.numeric(p[2])
pay <- switch(p[1], card = new("Card", amount = amount), cash = new("Cash", amount = amount))
cat(receipt(pay), "\n", sep = "")
total <- total + amount + fee(pay)
}
cat(sprintf("charged: %.2f", total), "\n", sep = "")
cat("Payment is virtual: ", isVirtualClass("Payment"), "\n", sep = "")
cat(tryCatch({ new("Payment", amount = 1); "created a Payment" }, error = function(e) "cannot create a Payment"), "\n", sep = "")
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы S3
Работа с файламиСписки с классомФункции-конструкторыМетоды print и formatВалидаторы и вспомогательные функцииПовторение — температуры4Инкапсуляция в R
Замыкания как объектыОкружения как объектыФункции доступаЗащита состоянияПовторение — парковочный счётчик7S4 Наследование
Расширение с помощью containscallNextMethodВиртуальные классыПроверка типов с помощью is()Повторение — смотритель зоопарка10Шаблоны проектирования, часть 2
Шаблон «Декоратор»Шаблон «Строитель»Шаблон «Состояние»Шаблон «Итератор»2Обобщённые функции и методы S3
Обобщённые функции и UseMethodМетоды по умолчаниюМетоды для базовых обобщённых функцийОсновы NextMethodПовторение — площади фигур5Классы S4
Определение классов S4Слоты и доступПроверка корректностиМетоды showПовторение — каталог товаров8Ссылочные классы
Определение ссылочных классовМетоды и обновление полейСемантика копированияНаследование и callSuperПовторение — очередь задач11Проект: Управление библиотекой
Книги и читателиВыдача книг3Наследование S3
Векторы классовПорядок поиска методовРасширение с помощью NextMethodПроверка с помощью inherits()Повторение — расчёт зарплаты сотрудниковПотренируйтесь самостоятельно: Онлайн-компилятор R