callNextMethod
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 33/57。
S4メソッド内で、callNextMethod()は同じ引数を使って親クラスのメソッドを呼び出し、その結果を返します。子メソッドは親の答えを繰り返すのではなく、それを基に処理を構築します:
setClass("Employee", slots = c(name = "character", salary = "numeric"))
setClass("Manager", contains = "Employee", slots = c(reports = "numeric"))
invisible(setGeneric("describe", function(x) standardGeneric("describe")))
setMethod("describe", "Employee", function(x) paste(x@name, "earns", x@salary))
setMethod("describe", "Manager", function(x) paste(callNextMethod(), "and manages", x@reports))
print(describe(new("Manager", name = "Ada", salary = 60000, reports = 4)))出力:
[1] "Ada earns 60000 and manages 4"show()でも機能します。子クラスは親クラスの行を出力してから、自身の行を出力します。
setClass("Employee", slots = c(name = "character"))
setClass("Manager", contains = "Employee", slots = c(reports = "numeric"))
setMethod("show", "Employee", function(object) cat("Employee:", object@name, "\n"))
setMethod("show", "Manager", function(object) {
callNextMethod()
cat("Reports:", object@reports, "\n")
})
new("Manager", name = "Ada", reports = 4)出力:
Employee: Ada
Reports: 4 new() はジェネリックな initialize() を呼び出します。これに対するメソッドでは、他のスロットから算出されるスロットを埋めることができます。まず callNextMethod(.Object, ...) を呼び出すため、通常のセットアップと妥当性チェックも引き続き行われます。
setClass("Order", slots = c(prices = "numeric", total = "numeric"))
setMethod("initialize", "Order", function(.Object, ...) {
.Object <- callNextMethod(.Object, ...)
.Object@total <- sum(.Object@prices)
.Object
})
o <- new("Order", prices = c(2.5, 4, 1))
print(o@total)出力:
[1] 7.5S3 の NextMethod() と同様に、callNextMethod() は複数のレベルを順にたどり、各クラスがそれぞれの処理を追加します。
setClass("Ticket", slots = c(base = "numeric"))
setClass("Vip", contains = "Ticket")
setClass("Backstage", contains = "Vip")
invisible(setGeneric("price", function(t) standardGeneric("price")))
setMethod("price", "Ticket", function(t) t@base)
setMethod("price", "Vip", function(t) callNextMethod() * 2)
setMethod("price", "Backstage", function(t) callNextMethod() + 50)
cat(price(new("Ticket", base = 30)), price(new("Vip", base = 30)), price(new("Backstage", base = 30)))出力:
30 60 110チャレンジ
簡単チケットは3つのレベルに分かれており、それぞれが独自のファイルに入っています。クラスとジェネリックな price() は宣言済みです。メソッドを追加してください:
Ticket.R:price()は基本価格を返し、show()はTicket for galaと改行を出力します。Vip.R:price()はチケット価格の1.5倍を返し、show()はチケットの行を出力してからVIP lounge accessを出力します。Backstage.R:price()はVIP価格に50を加えた値を返し、show()はVIPの行を出力してからBackstage passを出力します。
サブクラスのメソッドでは callNextMethod() を使用してください。提供されているコードは vip gala 80(レベル、イベント、基本価格)という行を読み取り、各チケットとその価格を出力します。
コードは Ticket.R、Vip.R、Backstage.R に記述します。main.R には提供された入出力コードが含まれており、編集できません。
自分で試してみよう
source("Ticket.R")
source("Vip.R")
source("Backstage.R")
# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
base <- as.numeric(p[3])
t <- switch(p[1],
standard = new("Ticket", event = p[2], base = base),
vip = new("VipTicket", event = p[2], base = base),
backstage = new("BackstageTicket", event = p[2], base = base))
print(t)
cat(sprintf("price: %.2f", price(t)), "\n", sep = "")
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ