2016-03-14 2 views
0

Я создал несколько методов S3, которые я контролирую, задавая классы для объекта. Что-то вроде этого:Объединение методов S3

myfun <- function (x) { 
    UseMethod("myfun") 
} 

myfun.a <- function(x) { 
    print("Type a") 
} 

myfun.b <- function(x) { 
    print("Type b") 
} 

myfun.c <- function(x) { 
    print("Type c") 
} 

myfun(structure(c(1:3), class = "a")) 
# [1] "Type a" 
myfun(structure(c(1:3), class = "b")) 
# [1] "Type b" 
myfun(structure(c(1:3), class = "c")) 
# [1] "Type c" 

Иногда некоторое подмножество классов способны делить метод что-то вроде этого:

otherfun <- function (x) { 
    UseMethod("otherfun") 
} 

otherfun.a <- function(x) { 
    print("Type a") 
} 

otherfun.b <- function(x) { ## Doesn't work because its only called for "b" 
    print("Type b or c") 
} 

otherfun(structure(c(1:3), class = "a")) 
# [1] "Type a" 
otherfun(structure(c(1:3), class = "b")) 
# [1] "Type b or c" 
otherfun(structure(c(1:3), class = "c")) 
# [1] "Type b or c" 

Что является лучшим/наиболее правильным способом реализации несколько типов классов Подселения метод? Я не хочу ставить классы на объект, потому что классы «b» и «c» различаются в большинстве аспектов.

Я думал об использовании метода по умолчанию и вручную разборе типа класса, что-то вроде:

otherfun <- function (x) { 
UseMethod("otherfun") 
} 

otherfun.a <- function(x) { 
    print("Type a") 
} 

otherfun.b <- function(x) { 
    print("Type b or c") 
} 

otherfun.default <- function(x) { 
    if(class(x) == "c") otherfun.b(x) 
    else stop("Bad Class on x") 
} 

otherfun(structure(c(1:3), class = "a")) 
# [1] "Type a" 
otherfun(structure(c(1:3), class = "b")) 
# [1] "Type b or c" 
otherfun(structure(c(1:3), class = "c")) 
# [1] "Type b or c" 

ответ

4

Просто назначьте их вместе, как это:

otherfun.b <- otherfun.c <- function(x) print("Type b or c") 
+0

Мне это нравится, спасибо ... Я буду принимать это как ответ завтра. –

4

Определить соответствующий класс hierarcy

a <- structure(list(), class=c("a", "base")) 
b <- structure(list(), class=c("b", "b_or_c", "base")) 
c <- structure(list(), class=c("c", "b_or_c", "base")) 

и применять методы в соответствующих местах

im <- function(x) UseMethod("im") 
im.a <- function(x) "I'm a" 
im.b_or_c <- function(x) paste("I'm b_or_c:", class(x)[1]) 

В действии:

> im(a) 
[1] "I'm a" 
> im(b) 
[1] "I'm b_or_c: b" 
> im(c) 
[1] "I'm b_or_c: c" 

Обычно классы акций методы из-за общей структуры. Определение соответствующей иерархии позволяет повторно использовать как метод, так и структуру данных.

Объекты одного класса должны всегда иметь одну и ту же иерархию классов, поэтому «b» всегда будет «b_or_c». Это применяется во многих объектных системах; S3 позволяет вам играть очень быстро и свободно с определениями классов. Один из способов для обеспечения общей иерархии является использование «конструкторов», которые централизовать создание класса

base = function(base_data="base only", ..., class) 
    ## construct an instance that contains base data, other data (...), 
    ## and an appropriate class specification 
    structure(list(base_data=base_data, ...), class=c(class, "base")) 

b_or_c = function(b_or_c_data="b or c", ..., class) 
    ## construct a b_or_c instance with relevant data, using the 
    ## base constructor 
    base(b_or_c_data=b_or_c_data, ..., class=c(class, "b_or_c")) 

b = function(b_data="b only", ...) 
    ## like b_or_c, but for a 'b' instance 
    b_or_c(b_data=b_data, ..., class="b") 

который в действии выглядит как

> b(b_data="ima b") 
$base_data 
[1] "base only" 

$b_or_c_data 
[1] "b or c" 

$b_data 
[1] "ima b" 

attr(,"class") 
[1] "b"  "b_or_c" "base" 

Даже если нет методов на b_or_c, это может по-прежнему полезно, чтобы класс представлял данные, которые совместно используются классами b и c. Если нет, удалите конструктор b_or_c и настройте b(), чтобы позвонить base().

Возможно, a использует метод с b и c, и в этом случае метод должен быть реализован в базовом классе. Когда a делит метод с b, но не c, тогда типично писать вспомогательную функцию, которую вызовут методы a и b после начальной обработки; Часто этот вид рисунка (где метод реализуется на объектах только из некоторых классов в разных частях иерархии) свидетельствует о том, что иерархия классов не предназначен надлежащим образом

.foo_helper = function(x) { 
    ## implement shared functionality here 
} 

foo.a = function(x) { 
    ## do a-specfic things here, then 
    data = some_manipulation_of_a 
    .foo_helper(data) 
} 

foo.b = function(x) { 
    data = some_manipulation_of_b 
    .foo_helper(data) 
} 

Вероятно, это было бы более реалистичной картина, чем принятый ответ - a и c, вероятно, потребуют отдельной обработки (поскольку они имеют разные структуры данных) перед вызовом некоторых общих функций.

+0

Спасибо, что напомнили мне сохранить базовый класс в списке классов. Однако я собираюсь принять ответ @ g-grothendieck. Ваш стиль выглядит намного сложнее в обслуживании и использовании. Например, я помещаю все объекты «b» и «c» в «b_or_c» или только те, которые, как я полагаю, нуждаются в смешанных методах? Что делать, если все смешанные методы удаляются в пользу уникальных методов? Что делать, если я понимаю, что «a» может поделиться методом с «c» в какой-то момент? –

+0

Я немного поработал в своем ответе. –

Смежные вопросы