Есть ли способ инициализировать объект 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
) и использование значения по умолчанию.