Menu
Coddy logo textTech

Classes virtuelles

Fait partie de la section Programmation orientée objet du Journey R de Coddy. Leçon 34 sur 57.

Une classe virtuelle décrit ce qu’une famille de classes a en commun et ne peut pas avoir ses propres objets. Déclarez-la avec representation("VIRTUAL") ; ses sous-classes utilisent contains comme d’habitude :

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

Sortie :

TRUE TRUE 
not allowed 

Une méthode pour la classe virtuelle fonctionne pour chaque sous-classe. Ici, describe() pour Shape appelle area(), que chaque sous-classe implémente, donc la description n’est écrite qu’une seule fois :

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

Sortie :

Circle with area 3.14 
Square with area 4.00 

Une classe virtuelle peut déclarer des slots, que chaque sous-classe possède ensuite :

setClass("Shape", representation("VIRTUAL", label = "character"))
setClass("Square", contains = "Shape", slots = c(side = "numeric"))
sq <- new("Square", label = "tile", side = 2)
print(slotNames("Square"))

Sortie :

[1] "side"  "label"

setClassUnion() crée une classe virtuelle à partir de classes existantes. Un slot de ce type accepte n’importe laquelle d’entre elles, comme un contact qui est soit une adresse e-mail, soit un numéro de téléphone :

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

Sortie :

character numeric 
refused 
challenge icon

Défi

Facile

Les paiements partagent la classe virtuelle Payment (slot amount) et les génériques fee() et receipt(), tous définis dans Payment.R. Complétez :

  • dans Payment.R, la méthode receipt() pour Payment : card: 100.00 + 2.00 fee, construite à partir du nom de classe en minuscules, de amount et de fee() ;
  • dans Card.R, la classe Card (qui contient Payment) et son fee() : 2 % du montant ;
  • dans Cash.R, la classe Cash et son fee() : 0.

Le code fourni lit les lignes card 100 ou cash 20, affiche chaque reçu et le montant total facturé, puis vérifie que Payment est virtuelle et ne peut pas être créée.

Votre code doit être placé dans Payment.R, Card.R et Cash.R. main.R contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

source("Payment.R")
source("Card.R")
source("Cash.R")

# Code d'entrée/sortie fourni : le garder tel quel
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 = "")
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur R en ligne