S3 và S4 dường như là các phương pháp tiếp cận chính thức (tức là tích hợp sẵn) cho lập trình OO. Tôi đã bắt đầu sử dụng kết hợp S3 với các hàm được nhúng trong hàm / phương thức của phương thức khởi tạo. Mục tiêu của tôi là có cú pháp kiểu object $ method () để tôi có các trường bán riêng tư. Tôi nói nửa riêng tư bởi vì không có cách nào thực sự che giấu chúng (theo như tôi biết). Đây là một ví dụ đơn giản mà không thực sự làm được gì:
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=''))
}
Và một số mã kiểm tra:
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')
Đây là liên kết đến một bài đăng trên blog mà tôi đã viết về cách tiếp cận này: http://bryer.org/2012/object-oriented-programming-in-r Tôi hoan nghênh các nhận xét, phê bình và đề xuất cho cách tiếp cận này vì tôi không bị thuyết phục bản thân tôi nếu đây là cách tiếp cận tốt nhất. Tuy nhiên, đối với vấn đề tôi đang cố gắng giải quyết, nó đã hoạt động rất tốt. Cụ thể, đối với gói makeR ( http://jbryer.github.com/makeR ), tôi không muốn người dùng thay đổi trường dữ liệu trực tiếp vì tôi cần đảm bảo rằng tệp XML đại diện cho trạng thái đối tượng của tôi sẽ luôn được đồng bộ hóa. Điều này hoạt động hoàn hảo miễn là người dùng tuân thủ các quy tắc tôi nêu trong tài liệu.