R和面向对象的编程

Pau*_*tra 78 oop r

在R中,以这种或那种方式进行面向对象的编程非常有可能.但是,与Python不同,有很多方法可以实现面向对象:

我的问题是:

哪些主要差异在R中区分这些OO编程方式?

理想情况下,这里的答案将作为R程序员的参考,试图决定哪种OO编程方法最适合他们的需求.

因此,我要求根据经验以客观的方式提供细节,并以事实和参考作为后盾.用于阐明这些方法如何映射到标准OO实践的奖励点.

Ari*_*man 33

S3班

  • 不是真正的对象,更多的是命名约定
  • 基于.语法:例如,用于打印,print调用print.lm print.anova等.如果没有找到,print.default

S4课程

参考类

  • ggplot2最初是用proto编写的,但最终会用S3重写.
  • 整洁的概念(原型,而不是类),但在实践中似乎很棘手
  • ggplot2的下一个版本似乎正在逐渐远离它
  • 描述概念和实现

R6班

  • 引用
  • 不依赖于S4课程
  • " 创建 R6类与引用类类似,不同之处在于不需要分隔字段和方法,也不能指定字段的类型."

  • 不要忘记`图书馆("财富"); 财富( "海峡")` (3认同)

Jos*_*ien 19

编辑于2012年3月8日:下面的答案回应了最初发布的问题,该问题已被删除.我在下面复制了它,为我的答案提供了上下文:

不同的OO方法如何映射到例如Java或Python中使用的更标准的OO方法?


我的贡献与你的第二个问题有关,关于R的OO方法如何映射到更标准的OO方法.正如我过去想到的那样,我一次又一次地回到两个段落,一个是Friedrich Leisch,另一个是John Chambers.两者都很好地阐明了为什么R中的类OO编程与许多其他语言的风格不同.

首先,Friedrich Leisch,来自"Creating R Packages:A Tutorial"(警告:PDF):

S很少见,因为它既具有交互性又具有面向对象的系统.清楚地设计类是编程,但是为了使S作为交互式数据分析环境有用,它是一种函数式语言是有道理的.在"真正的"面向对象编程(OOP)语言中,如C++或Java类和方法定义紧密绑定在一起,方法是类(以及对象)的一部分.我们希望增量和交互式添加,例如用于预定义类的用户定义方法.这些添加可以在任何时间点进行,甚至可以在我们分析数据集时在命令行提示符下进行.S试图在面向对象和交互式使用之间做出妥协,虽然妥协对于他们试图达到的所有目标来说永远不是最优的,但它们在实践中通常表现得非常好.

另一段来自John Chambers的精湛书籍"数据分析软件".(链接到引用的段落):

尽管S和其他一些函数语言支持类和方法,但OOP编程模型除了第一点之外都与S语言不同.OOP系统中的方法定义是该类的本地定义; 不要求方法的相同名称对于不相关的类意味着相同的事物.相反,R中的方法定义不存在于类定义中; 从概念上讲,它们与通用功能相关联.类定义直接或通过继承输入确定方法选择.习惯于OOP模型的程序员有时会感到沮丧或困惑,因为他们的编程不能直接传递给R,但它不能.方法的功能使用更复杂,但更适合于具有有意义的功能,并且不能简化为OOP版本.


jbr*_*yer 14

S3和S4似乎是OO编程的官方(即内置)方法.我已经开始使用S3与构造函数/方法中嵌入的函数的组合.我的目标是拥有一个对象$ method()类型语法,以便我有半私有字段.我说半私人,因为没有办法真正隐藏它们(据我所知).这是一个实际上没有做任何事情的简单示例:

#' Constructor
EmailClass <- function(name, email) {
    nc = list(
        name = name,
        email = email,
        get = function(x) nc[[x]],
        set = function(x, value) nc[[x]] <<- value,
        props = list(),
        history = list(),
        getHistory = function() return(nc$history),
        getNumMessagesSent = function() return(length(nc$history))
    )
    #Add a few more methods
    nc$sendMail = function(to) {
        cat(paste("Sending mail to", to, 'from', nc$email))
        h <- nc$history
        h[[(length(h)+1)]] <- list(to=to, timestamp=Sys.time())
        assign('history', h, envir=nc)
    }
    nc$addProp = function(name, value) {
        p <- nc$props
        p[[name]] <- value
        assign('props', p, envir=nc)
    }
    nc <- list2env(nc)
    class(nc) <- "EmailClass"
    return(nc)
}

#' Define S3 generic method for the print function.
print.EmailClass <- function(x) {
    if(class(x) != "EmailClass") stop();
    cat(paste(x$get("name"), "'s email address is ", x$get("email"), sep=''))
}
Run Code Online (Sandbox Code Playgroud)

还有一些测试代码:

    test <- EmailClass(name="Jason", "jason@bryer.org")
    test$addProp('hello', 'world')
    test$props
    test
    class(test)
    str(test)
    test$get("name")
    test$get("email")
    test$set("name", "Heather")
    test$get("name")
    test
    test$sendMail("jbryer@excelsior.edu")
    test$getHistory()
    test$sendMail("test@domain.edu")
    test$getNumMessagesSent()

    test2 <- EmailClass("Nobody", "dontemailme@nowhere.com")
    test2
    test2$props
    test2$getHistory()
    test2$sendMail('nobody@exclesior.edu')
Run Code Online (Sandbox Code Playgroud)

这是我写的关于这种方法的博客文章的链接:http://bryer.org/2012/object-oriented-programming-in-r我会欢迎对这种方法的评论,批评和建议,因为我不相信我自己,如果这是最好的方法.但是,对于我试图解决的问题,它运作得很好.具体来说,对于makeR包(http://jbryer.github.com/makeR),我不希望用户直接更改数据字段,因为我需要确保代表我的对象状态的XML文件保持同步.只要用户遵守我在文档中列出的规则,这就完美无缺.

  • 你可以用上面的代码"手动"重新发明引用类......这只会让事情变得更加脆弱. (10认同)