有没有办法为 S4 参考类声明公共和私有方法?
Posted
技术标签:
【中文标题】有没有办法为 S4 参考类声明公共和私有方法?【英文标题】:Is there a way to declare public and private methods for S4 Reference Classes? 【发布时间】:2012-06-19 20:33:18 【问题描述】:预先说明:我我知道 R 是一种函数式语言,所以请不要咬 ;-)
在我的许多程序中使用 OOP 方法时,我有很棒的经验。 现在,我想知道在 R 中使用 S4 Reference Classes 时是否有办法区分 public 和 private 方法?
示例
类定义
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"
)
)
注意
我通常不会将 actual 方法定义放在类 def 中,而是将其分隔为 S4 方法(即thisIsPublic_ref
),原因如下:
-
这样,类 def 可以保持清晰的排列,并且在单个方法 def 变得非常大的情况下更易于阅读。
它允许您随时切换到功能方法的执行。成为
x
某个类的实例,您可以调用foo_ref(.self=x)
而不是x$foo()
。
它允许您通过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")
公共与私人
应该允许A
类的实例(即x.a
)使用B
类的public 方法:
> x.a$a.1$thisIsPublic()
[1] 10000
A
类的实例(即x.a
)应该不允许使用B
类的私有 方法。所以我希望这个 not 起作用,即导致错误:
> x.a$a.1$thisIsPrivate()
[1] TRUE
知道如何指定这一点吗?
到目前为止我唯一想到的:
为每个方法添加一个sender
参数,为每个方法调用显式指定它并检查是否class(.self) == class(sender)
。但这似乎有点“明确”。
【问题讨论】:
x.a 是 A 类的实例,但 x.a$a.1 是 B 类的实例。您想阻止 B 类的实例访问 B 类的私有方法吗?你可能会进入一个痛苦的世界,试图阻止一个类访问它的方法,这取决于它可能发生在什么样的数据结构中...... 完全正确,这不是我的目标。同样,这是一个我觉得我只是缺乏一些关于 OOP 的背景知识的话题。将某些类的实例放在其他类的字段中(即,x.a$a.1
作为类x.a
中A
的类B
的实例)只是我实现某种程度封装的方式。但是您完全正确,这种方式实际上不可能区分公共方法和私有方法,因为最终调用该方法的是a.1
,而不是x.a
。我会考虑对我的示例进行很好的更新,以使事情更清楚。
【参考方案1】:
由于函数是 R 中的一等对象,您可以将一个嵌入另一个对象中,如下所示:
hello <- function()
print_ <- function()
return ('hello world')
print_()
是的,它很厚颜无耻,可能不是最干净的方式,但它确实有效...使用 'hello()' 调用。
【讨论】:
我一点也不觉得这很厚脸皮。这在 javascript 库中是相当标准的做法,在其他面向函数的脚本语言中看到它我不会感到惊讶。【参考方案2】:简短的回答是制作一个包。 R's object systems 和它的分区代码(命名空间)方式比它们在类 Java 语言中的等价物更加独立。
当您制作一个包时,您可以使用指令export
和exportMethods
指定在名为NAMESPACE 的文件中导出的内容。您可以选择不导出您希望包私有的方法和其他 R 对象(使用 Java 术语)。见Namespaces with S4 classes and methods section of the Writing R Extensions manual
第一次制作包很棘手,但有很多帮助。请参阅package.skeleton 的文档和上面链接的编写 R 扩展手册。
确保引用类确实是您想要的。常规的 S4 课程通常是更 R-ish 的方式,无论其价值如何。 Hadley Wickham's devtools wiki 上提供了有关 R 的许多 OO 构造(以及打包)的重要信息来源。
【讨论】:
我完全同意这一点,包是要走的路。但是请注意,不从包中导出某些内容并不意味着用户无法访问它。您仍然可以使用“:::
”运算符访问“私有”函数和数据。以上是关于有没有办法为 S4 参考类声明公共和私有方法?的主要内容,如果未能解决你的问题,请参考以下文章