槽赋值:`@`vs`slot()`vs`setReplaceMethod()`

时间:2014-03-20 22:37:29

标签: r s4

我正在编写我的第一个R包,我正在试图找出为S4对象中的插槽赋值的最佳方法,请记住最终用户不应该大惊小怪。正在使用S4类结构。以下哪项最好?

  1. 使用object@MySlot <- value直接访问广告位:

    我理解这种不良做法(例如,this Q&A)。

  2. 使用slot(object, "MySlot") <- value

    R帮助表示在获取值时没有检查,但是在设置时进行检查(假设check尚未设置为FALSE)。这对我来说听起来很合理,并且让我觉得这是一个很好的方法,因为我不需要编写我自己的get / set方法,如下所示。

  3. 将自定义方法与setReplaceMethod()一起使用:

    这种方法与上面的第二种方法相比如何?生成必要的get / set方法需要做更多的工作,但我可以更明确地确保写入插槽的值对该插槽类型有效。

    setGeneric("MySlot", function(object) {
        standardGeneric("MySlot")
    })
    
    setMethod("MySlot",
          signature = "MyClass",
          definition = function(object) {
              return(object@MySlot)
    })
    
    setGeneric("MySlot<-",
           function(object, value) {
               standardGeneric("MySlot<-")
    })
    
    setReplaceMethod("MySlot",
                 signature="MyClass",
                 function(object, value) {
                     object@MySlot<- value
                     validObject(object) # could add other checks
                     return(object)
    })
    

1 个答案:

答案 0 :(得分:4)

根据定义,“不必大惊小怪S4类结构的细节”意味着最终用户不应该知道您的插槽。因此,您在步骤2和3中编写的任何包装器都更适用于内部一致性检查。我认为更重要的是使用unit tests检查您认为完整性检查失败的边缘情况。

正如您所指出的,可以相当容易地排除#1,并且只应在内部方法中使用。无论你是鼓励#2还是实施#3取决于变量的内容和个人品味,但我会鼓励后者。例如,如果您有logical标记,则可以使用#2,但更具描述性的标记为enableFoo()。话虽这么说,如果你必须考虑开发人员的时间(在现实生活中几乎总是如此),你应该简单地考虑将可能不会经常访问的成员降级为slot<-之间的权衡(例如,不到1%的用户),而不是像#3那样为一切实现自定义变更器。

最后,因为几乎所有三个R的OOP系统本质上都是语法糖,并且在语言上没有真正受到语言的尊重(只有S4可以声称有一些例外),很容易忘记面向对象编程背后的基本思想用其他语言实现:在方法之外执行的任何代码都不应该知道对象的成员。您正在为世界提供一个外部接口,该接口应该是一个黑盒子。