补充我的评论,而不是为问题提供新的答案,这是一个我们仍然按位置匹配参数的解决方案(因为我们为 B 类指定了额外的表示):
.A <- setClass("A", representation(a="character"))
.B <- setClass("B", representation(b="numeric"),
prototype(a="hello"),
contains="A")
.A() 和 .B() 替换对 new("A") 和 new("B") 的调用。在某种程度上,这是语法糖,但可以使对象构造更加透明
## construct an object using B's prototype, like new("B", b=1:3)
> .B(b=1:3)
An object of class "B"
Slot "b":
[1] 1 2 3
Slot "a":
[1] "hello"
## construct an object using A's prototype, like new("B", new("A"), b=1:3)
> .B(.A(), b=1:3)
An object of class "B"
Slot "b":
[1] 1 2 3
Slot "a":
character(0)
(第二个示例使用 new 或 B 的未命名参数来初始化继承类的事实。
用户必须直接使用.A 或.B 不是很友好,例如,因为签名只是...,因此将记录为“查看A 类插槽的定义” '。这破坏了作为 OOP 优势的接口和实现的分离。此外,最后一个代码块(.B(.A(a=a), b=b) 或.B(a=a, b=b))中的一种或另一种行为可能不是本意。所以改为提供一个 向用户公开的函数,也许做一些初始数据按摩
A <- function(a=character(), ...) {
## nothing special, just a public constructor
.A(a=a, ...)
}
B <- function(b, a="hello", ...) {
a <- tolower(a) ## no SHOUTing!
.B(A(a=a), b=b) ## A's public interface; no need for B to know A's details
}
函数 A 和 B 定义接口,在不将构造函数与类定义绑定的情况下向用户提供有关可接受参数的提示,并执行初步数据按摩。后者可以使 initialize 方法变得不必要,这是一件好事,因为它们有一个 complicated contract (它们应该初始化 并且 是复制构造函数,正如我们在上面看到的未命名参数应该初始化基类)大多数人都会出错。
这些只是我的意见。