Программирование с использованием базового класса
Как определить несколько полиморфных конструкторов и функций, таких как
function Add( x, y : Integer ) : Integer; begin Add := x + y end; function Add( s, t : String ) : String; begin Add := Concat( s, t ) end; begin Writeln(Add(1, 2)); Writeln(Add('Hello, ', 'World!')); end.
Могу ли я сделать это только по решению вопроса, как
A<-setRefClass(Class = "A"
,fields = list(var1="character")
,methods = list(setFields=A.setFields
,initialize=function(var1) {
if(isClass(var1,"B"))
.self$var1<-as.character(var1$getFields("var1"))
else{
.self$var1<-as.character(var1)
}
.self
})
)
Как совместить функциональное программирование с объектно-ориентированным программированием. Поэтому, если бы я вызвал функции getFields(vecB), где vecB - это вектор или список объектов B. Возвращаемое значение должно быть значением каждого объекта?
B.getFields<-function(...,values){ vars<-mget(names(.refClassDef@fieldClasses), envir = attr(.self, ".xData")) if(missing(values)) return(vars) if(length(vars)==1) return(vars[[1]]) return(vars[names(vars) %in% values]) } B<-setRefClass(Class = "B" ,fields = list(var1 = "character") )
Как отладить, например, функцию инициализации из класса A? Я старался
A$trace("initialize") a<-A$new("ABC") initial<-a$initialize trace(initial,browser,where=A)
но это не работает.
2 ответа
Используйте S4 дженерики и методы для полиморфизма
setGeneric("Add", function(x, y) standardGeneric("Add")) setMethod(Add, c("numeric", "numeric"), function(x, y) x + y) setMethod(Add, c("character", "character"), function(x, y) paste0(x, y))
так
> Add(1, 2) [1] 3 > Add("hello ", "world") [1] "hello world" > Add("hello ", 2) Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'Add' for signature '"character", "numeric"'
Одна идея использовать этот универсальный в ссылочном классе
A <- setRefClass("A", fields=list(x="ANY"), methods=list( getX=function() { .self$x }, setX=function(x) { .self$x <- x .self }, addX=function(y) { setX(Add(getX(), y)) }, show=function() { cat("class:", class(.self), "\nx:", getX(), "\n") }))
с соответствующей диспетчеризацией для функционального стиля программы:
setMethod(Add, c("A", "ANY"), function(x, y) x$addX(y)) setMethod(Add, c("A", "A"), function(x, y) x$addX(y$getX()))
(может быть, для функционального программирования имеет смысл реализовать
$addX()
какA(.self, x=Add(x$getX(), y))
создание клона х?) для> Add(A(x=1), A(x=2)) class: A x: 3 > Add(A(x="hello "), "world") class: A x: hello world > A(x=2)$addX(3) class: A x: 5
хотя и не
A(x=1)$addX(A(x=2))
Посмотрите этот ответ для одного подхода к возвращению значений поля:
B = setRefClass("B", fields=c(var1="list", var2="character"), methods=list(getFields=function(values) { flds = names(getRefClass()$fields()) if (!missing(values)) flds = flds[flds %in% values] result = setNames(vector("list", length(flds)), flds) for (fld in flds) result[[fld]] = .self[[fld]] result }))
Один из способов функционального вызова требует отдельной реализации, например:
setGeneric("getFields", function(x, ...) standardGeneric("getFields")) setMethod(getFields, "B", function(x, ...) x$getFields(...)) setMethod(getFields, "list", function(x, ...) lapply(x, getFields, ...))
Ваш пример класса А неполный.
A <- setRefClass("A", methods=list(initialize=function(...) { message("hello A") callSuper(...) }))
а потом
> A$trace("initialize", browser) Tracing reference method "initialize" for class "A" [1] "initialize" > A() Tracing .Object$initialize(...) on entry Called from: eval(expr, envir, enclos) Browse[1]> n debug: { message("hello A") callSuper(...) } Browse[2]> n debug: message("hello A") Browse[2]>
Вот предыдущее обсуждение полиморфизмов в R: Каковы рекомендуемые практики для полиморфизма функций в R?
Способ связать строку с помощью вставки.
paste("Hello, ","world",sep="")