仮想クラス
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 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 仮想クラスのメソッドは、すべてのサブクラスで機能します。ここでは、Shape の describe() が area() を呼び出します。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.R に定義された仮想クラス Payment(スロット amount)とジェネリック fee() および receipt() を共有します。以下を完成させてください。
Payment.Rで、Paymentに対するreceipt()メソッドを実装します。これは、クラス名を小文字にしたもの、amount、およびfee()から構成されるcard: 100.00 + 2.00 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 = "")
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ