我正在编写我的第一个R包,我正在试图找出为S4对象中的插槽赋值的最佳方法,请记住最终用户不应该大惊小怪。正在使用S4类结构。以下哪项最好?
使用object@MySlot <- value
直接访问广告位:
我理解这种不良做法(例如,this Q&A)。
使用slot(object, "MySlot") <- value
:
R帮助表示在获取值时没有检查,但是在设置时进行检查(假设check
尚未设置为FALSE
)。这对我来说听起来很合理,并且让我觉得这是一个很好的方法,因为我不需要编写我自己的get / set方法,如下所示。
将自定义方法与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)
})
答案 0 :(得分:4)
根据定义,“不必大惊小怪S4类结构的细节”意味着最终用户不应该知道您的插槽。因此,您在步骤2和3中编写的任何包装器都更适用于内部一致性检查。我认为更重要的是使用unit tests检查您认为完整性检查失败的边缘情况。
正如您所指出的,可以相当容易地排除#1,并且只应在内部方法中使用。无论你是鼓励#2还是实施#3取决于变量的内容和个人品味,但我会鼓励后者。例如,如果您有logical
标记,则可以使用#2,但更具描述性的标记为enableFoo()
。话虽这么说,如果你必须考虑开发人员的时间(在现实生活中几乎总是如此),你应该简单地考虑将可能不会经常访问的成员降级为slot<-
之间的权衡(例如,不到1%的用户),而不是像#3那样为一切实现自定义变更器。
最后,因为几乎所有三个R的OOP系统本质上都是语法糖,并且在语言上没有真正受到语言的尊重(只有S4可以声称有一些例外),很容易忘记面向对象编程背后的基本思想用其他语言实现:在方法之外执行的任何代码都不应该知道对象的成员。您正在为世界提供一个外部接口,该接口应该是一个黑盒子。