Чем отличается метод инициализации от прототипа в setClass для установки значений по умолчанию в R S4? - PullRequest
1 голос
/ 05 апреля 2020

В R S4 OOP мне известны 2 способа, поэтому установите значения по умолчанию для определенного класса.

1.) Использование прототипа в setClass()

setClass("Person",
         slots = c(
           name = "character",
           age = "numeric"
         ), 
         prototype = list(
           name = "Jim",
           age = 25
         )
         )

2.) Использование инициализации в setMethod()

setMethod("initialize", "Person",
          function(.Object,
                   name,
                   age,
                   ...) {
              .Object@name <- "Jim"
              .Object@age <- 25
            validObject(.Object)
            return(.Object)
          }
)

assign("Person", Person, envir = .GlobalEnv)

Может ли кто-нибудь подробно рассказать о различии между этими двумя, то есть, почему мы хотим включить отдельный метод инициализации против использования prototype() в setClass()? Какова лучшая практика S4?

Заранее спасибо за ответ.

1 Ответ

1 голос
/ 07 апреля 2020

Прототип способен обрабатывать только простые случаи; в частности, значение слотов не может зависеть друг от друга, и пользователь не может указывать какие-либо значения Dynami c. Например, если у вас есть простой класс

setClass("personInfo",
  slots=list(
    age="numeric",
    ageSquared="numeric"
  ), prototype=prototype(
    age=18,
    ageSquared=18^2
) -> personInfo

, то прототип может создавать только 18-летние люди. Вместо этого более полезно создать метод инициализации как функцию age, которая затем может установить для age и ageSquared соответствующие значения.

Также обратите внимание, что если вы присваиваете результаты setClass в объект (как я делал в примере выше, назначение его в объект с именем personInfo, тогда personInfo становится вызовом initialize, и теперь вы можете вызвать, например,

personInfo(age=10,ageSquared=100)

(хотя в данном случае это не идеально, так как вы должны явно указать ageSquared, если бы у вас был такой метод для вас.)

Я бы порекомендовал:

  • с использованием прототипа для любого слота, который имеет разумное значение по умолчанию (каждый класс / слот в любом случае имеет неявный прототип)
  • всегда сохраняя возвращаемое значение из setClass как объект
  • переопределяет это методом initialize, если некоторые слоты зависят от других (например, ageSquared здесь)
...