Предварительно: я знаю, что R — это функциональный язык, поэтому, пожалуйста, не кусайтесь ;-)
У меня был отличный опыт использования ООП-подхода для многих моих программ. Теперь мне интересно, есть ли способ провести различие между public и private методами при использовании Справочные классы S4 в 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"
)
)
ПРИМЕЧАНИЕ
Обычно я не помещаю определение метода фактического в определение класса, а выделяю его в метод S4 (т. е. thisIsPublic_ref
) по следующим причинам:
- Таким образом, определение класса остается четко организованным и его легче читать в случаях, когда определения отдельных методов становятся довольно большими.
- Он позволяет в любой момент переключиться на функциональное выполнение методов. Будьте
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
) должно быть разрешено использовать public методы класса B
:
> x.a$a.1$thisIsPublic()
[1] 10000
Экземплярам класса A
(т. е. x.a
) не разрешается использовать частные методы класса B
. Поэтому я бы хотел, чтобы это не работало, т.е. приводило к ошибке:
> x.a$a.1$thisIsPrivate()
[1] TRUE
Любая идея, как можно указать это?
Единственное, что я пока придумал:
Добавляя аргумент sender
к каждому методу, явно указывайте его для каждого вызова метода и проверяйте, не является ли class(.self) == class(sender)
. Но это кажется немного «явным».
x.a$a.1
в качестве экземпляра классаB
вx.a
классаA
) было просто моим способом реализации некоторой степени инкапсуляции. Но вы совершенно правы в том, что таким образом невозможно различить общедоступные и частные методы, поскольку в конце концов метод вызываетсяa.1
, а неx.a
. Я подумаю о хорошем обновлении моего примера, чтобы прояснить ситуацию. - person Rappster   schedule 28.08.2012