24

预先:我知道 R 是一种函数式语言所以请不要咬 ;-)

在我的许多程序中使用 OOP 方法时,我有很好的经验。现在,我想知道在 R 中使用S4 引用类时是否有办法区分公共方法和私有方法?

例子

类定义

setRefClass("B",
    field=list(
        b.1="numeric",
        b.2="logical"
    ),
    methods=list(
        thisIsPublic=function(...) {
            thisIsPublic_ref(.self=.self, ...)
        },
        thisIsPrivate=function(...) {
            thisIsPrivate_ref(.self=.self, ...)
        }
    )
)

setRefClass("A",
    field=list(
        a.1="B"
    )
)

笔记

我通常不会将实际的方法定义放在类 def 中,而是将其与 S4 方法(即thisIsPublic_ref)分开,原因如下:

  1. 这样,类 def 保持清晰的排列,并且在单个方法 def 变得非常大的情况下更易于阅读。
  2. 它允许您随时切换到方法的功能执行。作为x某个类的实例,您可以调用foo_ref(.self=x)而不是x$foo().
  3. compiler::cmpfun()如果您有“普通”参考类方法,它允许您对我认为不可能的方法进行字节编译。

对于这个具体的例子来说,把它弄得那么复杂肯定没有什么意义,但我想我还是会说明这种方法。

方法定义

setGeneric(
    name="thisIsPublic_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPublic_ref")    
    }
)
setGeneric(
    name="thisIsPrivate_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPrivate_ref")    
    }
)

require(compiler)

setMethod(
    f="thisIsPublic_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.1 * 1000
    })
)
setMethod(
    f="thisIsPrivate_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.2
    })
)

实例

x.b <- new("B", b.1=10, b.2=TRUE)
x.a <- new("A", a.1=x.b, a.2="hello world")

公共与私人

应该允许class A(ie )的实例使用 class的公共方法:x.aB

> x.a$a.1$thisIsPublic()
[1] 10000

不应允许class A(ie x.a)的实例使用 class的私有方法。所以我希望这不起作用,即导致错误:B

> x.a$a.1$thisIsPrivate()
[1] TRUE

知道如何指定这一点吗?

到目前为止我唯一想到的:

为每个方法添加一个sender参数,为每个方法调用显式指定它并检查 if class(.self) == class(sender)。但这似乎有点“明确”。

4

2 回答 2

8

由于函数是 R 中的一等对象,您可以将一个嵌入另一个对象中,如下所示:

hello <- function() {
    print_ <- function() { 
         return ('hello world')
    }
    print_()
}

是的,它很厚颜无耻,可能不是最干净的方式,但它确实有效......使用'hello()'调用。

于 2012-09-27T15:28:22.450 回答
3

简短的回答是制作一个包裹。R 的对象系统及其划分代码(命名空间)的方法比它们在类 Java 语言中的等价物更加独立。

当你制作一个包时,你可以使用指令exportexportMethods. 您可以选择不导出您希望包私有的方法和其他 R 对象(使用 Java 术语)。请参阅编写 R 扩展手册的具有 S4 类和方法的命名空间部分

第一次做一个包是很棘手的,但有很多帮助。请参阅上面链接的package.skeleton文档和编写 R 扩展手册。

确保参考类真的是你想要的。常规的 S4 课程通常是更 R-ish 的方式,无论其价值如何。Hadley Wickham 的 devtools wiki上提供了有关 R 的许多 OO 构造(以及打包)的重要信息来源。

于 2012-08-30T06:09:38.280 回答