【问题标题】:slot assignment: `@` vs `slot()` vs `setReplaceMethod()`插槽分配:`@` vs `slot()` vs `setReplaceMethod()`
【发布时间】:2014-03-20 22:37:29
【问题描述】:

我正在编写我的第一个 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)
    })
    

【问题讨论】:

    标签: r s4


    【解决方案1】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-04
      • 1970-01-01
      • 2016-04-01
      • 2011-02-15
      • 2012-02-14
      • 2016-01-15
      • 2011-09-19
      • 1970-01-01
      相关资源
      最近更新 更多