S3 und S4 scheinen die offiziellen (dh eingebauten) Ansätze für die OO-Programmierung zu sein. Ich habe begonnen, eine Kombination von S3 mit Funktionen zu verwenden, die in die Konstruktorfunktion / -methode eingebettet sind. Mein Ziel war es, eine Syntax vom Typ object $ method () zu haben, damit ich halbprivate Felder habe. Ich sage halbprivat, weil es keine Möglichkeit gibt, sie wirklich zu verstecken (soweit ich weiß). Hier ist ein einfaches Beispiel, das eigentlich nichts tut:
EmailClass <- function(name, email) {
nc = list(
name = name,
email = email,
get = function(x) nc[[x]],
set = function(x, value) nc[[x]] <<- value,
props = list(),
history = list(),
getHistory = function() return(nc$history),
getNumMessagesSent = function() return(length(nc$history))
)
nc$sendMail = function(to) {
cat(paste("Sending mail to", to, 'from', nc$email))
h <- nc$history
h[[(length(h)+1)]] <- list(to=to, timestamp=Sys.time())
assign('history', h, envir=nc)
}
nc$addProp = function(name, value) {
p <- nc$props
p[[name]] <- value
assign('props', p, envir=nc)
}
nc <- list2env(nc)
class(nc) <- "EmailClass"
return(nc)
}
print.EmailClass <- function(x) {
if(class(x) != "EmailClass") stop();
cat(paste(x$get("name"), "'s email address is ", x$get("email"), sep=''))
}
Und ein Testcode:
test <- EmailClass(name="Jason", "jason@bryer.org")
test$addProp('hello', 'world')
test$props
test
class(test)
str(test)
test$get("name")
test$get("email")
test$set("name", "Heather")
test$get("name")
test
test$sendMail("jbryer@excelsior.edu")
test$getHistory()
test$sendMail("test@domain.edu")
test$getNumMessagesSent()
test2 <- EmailClass("Nobody", "dontemailme@nowhere.com")
test2
test2$props
test2$getHistory()
test2$sendMail('nobody@exclesior.edu')
Hier ist ein Link zu einem Blog-Beitrag, den ich über diesen Ansatz geschrieben habe: http://bryer.org/2012/object-oriented-programming-in-r Ich würde Kommentare, Kritik und Vorschläge zu diesem Ansatz begrüßen, da ich nicht überzeugt bin ich selbst, wenn dies der beste Ansatz ist. Für das Problem, das ich zu lösen versuchte, hat es jedoch großartig funktioniert. Insbesondere für das makeR-Paket ( http://jbryer.github.com/makeR ) wollte ich nicht, dass Benutzer Datenfelder direkt ändern, da ich sicherstellen musste, dass eine XML-Datei, die den Status meines Objekts darstellt, synchron bleibt. Dies funktionierte einwandfrei, solange die Benutzer die in der Dokumentation beschriebenen Regeln einhalten.