结合S3方法

时间:2016-03-14 21:24:27

标签: r

我通过在对象上设置类来创建几个我控制的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"

实现共享方法的多个类类型的最佳/最正确方法是什么?我不想在对象上堆栈类,因为课程&#34; b&#34;和&#34; c&#34;在大多数方面都不同。

我正在考虑使用默认方法并手动解析类类型,例如:

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"

2 个答案:

答案 0 :(得分:4)

只需将它们分配到一起:

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

答案 1 :(得分:4)

定义合适的班级层次

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()

可能是abc共享方法,在这种情况下,该方法应该在基类上实现。当ab但不是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)
}

可能这是一个比接受的答案更真实的模式 - ac可能需要单独处理(因为它们有不同的数据结构),然后再调用一些共享功能。