Предварително: съм наясно, че R е функционален език, така че, моля, не хапете ;-)
Имам страхотен опит с използването на ООП подход за много от моите програми. Сега се чудя дали има начин да се направи разлика между публични и частни методи, когато се използва Референтни класове на 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"
)
)
ЗАБЕЛЕЖКА
Обикновено не поставям действителната дефиниция на метода в класа def, а я отделям към 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
) трябва да имат право да използват публичните методи на клас 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