メソッド探索順序
CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 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各ジェネリックはそれぞれ個別に検索されます。1つのオブジェクトが自身のクラスからsound()を取得し、親からmove()を取得することもできます。また、親のメソッドが、子に対して再びディスパッチされる別のジェネリックを呼び出すこともできます。
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"class属性を持つオブジェクトの場合、ディスパッチはその属性だけを確認し、その後デフォルトを確認します。オブジェクトの内部は依然としてリストですが、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チャレンジ
簡単正方形は、辺の長さが等しい長方形です。Rectangle.R に、rectangle 2x3 を返すメソッド area.rectangle()、perimeter.rectangle()、name.rectangle() を記述してください。Square.R では、クラス square を指定して new_rectangle() を呼び出す new_square(side) を完成させ、name.square() によって name() だけをオーバーライドし、square 2 を返すようにしてください。正方形は長方形の area() と perimeter() を使用する必要があります。
ジェネリック関数と new_rectangle() は用意されています。提供されたコードは、2つの数値(長方形)または1つの数値(正方形)を含む行を読み取り、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 = "")
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rオンラインコンパイラ