Up-front: я am знает, что R - функциональный язык, поэтому, пожалуйста, не кусайте; -)
У меня был опыт большой с использованием подхода ООП для многих моих программ. Теперь мне интересно, есть ли способ провести различие между публичными и частными методами при использовании S4 Reference Classes в R?
Пример
Определения классов
setRefClass("B",
field=list(
b.1="numeric",
b.2="logical"
),
methods=list(
thisIsPublic=function(...) {
thisIsPublic_ref(.self=.self, ...)
},
thisIsPrivate=function(...) {
thisIsPrivate_ref(.self=.self, ...)
}
)
)
setRefClass("A",
field=list(
a.1="B"
)
)
Примечание
Я обычно не помещаю определение фактического метода в класс def, но разделяю его на метод S4 (т.е. thisIsPublic_ref
) по следующим причинам:
- Таким образом, класс def остается четко организованным и его легче читать в случаях, когда индивидуальный метод defs становится довольно большим.
- Он позволяет в любое время переключиться на функциональное выполнение методов. Be
x
экземпляр определенного класса, вы можете вызватьfoo_ref(.self=x)
вместоx$foo()
. - Это позволяет вам байт-компилировать методы с помощью
compiler::cmpfun()
, который, как я думаю, невозможен, если у вас есть "простые" методы ссылочного класса.
Конечно, не имеет смысла делать это сложным для этого конкретного примера, но я думал, что все же проиллюстрирую этот подход.
Определения методов
setGeneric(
name="thisIsPublic_ref",
signature=c(".self"),
def=function(
.self,
...
) {
standardGeneric("thisIsPublic_ref")
}
)
setGeneric(
name="thisIsPrivate_ref",
signature=c(".self"),
def=function(
.self,
...
) {
standardGeneric("thisIsPrivate_ref")
}
)
require(compiler)
setMethod(
f="thisIsPublic_ref",
signature=signature(.self="B"),
definition=cmpfun(function(
.self,
...
){
.self$b.1 * 1000
})
)
setMethod(
f="thisIsPrivate_ref",
signature=signature(.self="B"),
definition=cmpfun(function(
.self,
...
){
.self$b.2
})
)
Экземпляры
x.b <- new("B", b.1=10, b.2=TRUE)
x.a <- new("A", a.1=x.b, a.2="hello world")
Открытый и закрытый
Для экземпляров класса A
(т.е. x.a
) следует использовать методы класса B
public:
> x.a$a.1$thisIsPublic()
[1] 10000
Экземпляры класса A
(т.е. x.a
) должны иметь не, чтобы использовать методы класса B
private. Поэтому я хотел бы, чтобы этот не работал, то есть приводил к ошибке:
> x.a$a.1$thisIsPrivate()
[1] TRUE
Любая идея, как это можно было бы определить?
Единственное, что я придумал до сих пор:
Добавление аргумента sender
для каждого метода, явно указать его для каждого вызова метода и проверить, есть ли class(.self) == class(sender)
. Но это кажется немного "явным".