Есть ли способ инициализировать объект S4, чтобы был возвращен другой объект?

У меня есть иерархия классов с суперклассом fb из которых не должно быть никаких объектов (я пробовал виртуальные классы, но столкнулся с проблемой, что вы не можете инициализировать объекты из виртуальных классов). Далее у меня есть два подкласса (foo, bar) с такими же слотами. Теперь я хочу создать новый объект, используя метод initialize для суперкласса, который возвращает объект одного из подклассов на основе некоторого значения:

setClass("fb", representation( x = "numeric"))

setClass("foo", contains = "fb")
setClass("bar", contains = "fb")

setMethod("initialize", "fb", function(.Object, x) {
    if (x < 5) class(.Object) <- "foo"
    else class(.Object) <- "bar"
    .Object@x <- x
    .Object
})

> new("fb", x = 3)
Error in initialize(value, ...) : 
  initialize method returned an object of class "foo" instead of the required class "fb"

Очевидно (и, вероятно, по уважительным причинам) R запрещает это. Есть ли способ достичь того, что я хочу в методе, и не использовать конструкцию if-else при создании нового объекта?

1 ответ

Решение

S4 помогает нам раскрашивать линии. Так что ваши fb класс должен быть виртуальным, ваш initialize метод не должен изменять класс .Object, Вы могли бы написать функцию fb это делает ваше условное воплощение.

setClass("fb", representation( x = "numeric", "VIRTUAL"))
setClass("foo", contains = "fb")
setClass("bar", contains = "fb")

fb <-
    function(x)
{
    if (x < 5) new("foo", x=x)
    else new("bar", x=x)
}

fb это конструктор, более удобный для пользователя, который отделяет интерфейс к вашей иерархии классов от его реализации, что обычно считается хорошей вещью.

И для чего стоит неявное ограничение на S4 initialize методы в том, что new("foo") (ссылающееся new с именем класса, но без дополнительных аргументов) должен работать (в противном случае возникают ошибки при попытке расширить foo). Таким образом, парадигма для метода инициализации в соответствии с

setMethod(initialize, "foo", function(.Object, ..., x=1) {
    .Object <- callNextMethod(.Object, ...)
    .Object@x <- x
    .Object
})

хотя часто (как в этом случае, где initialize просто выполняет присваивание слотов) метод инициализации вообще не нужен. Обратите внимание на использование ..., позиционирование x (требуя, чтобы аргумент был назван в соответствующем вызове new) и использование значения по умолчанию.

Другие вопросы по тегам