R에서는 어떤 식 으로든 객체 지향 프로그래밍이 가능합니다. 그러나 예를 들어 Python과 달리 객체 지향을 달성하는 방법에는 여러 가지가 있습니다.
내 질문은 :
R에서 이러한 OO 프로그래밍 방식을 구별하는 주요 차이점은 무엇입니까 ?
이상적으로 여기에있는 답변은 자신의 요구에 가장 적합한 OO 프로그래밍 방법을 결정하려는 R 프로그래머를위한 참고 자료가 될 것입니다.
따라서 저는 경험을 바탕으로 객관적인 방식으로 제시되고 사실과 참고 자료로 뒷받침되는 세부 사항을 요청하고 있습니다. 명확히에 대한 보너스 포인트 방법 이 방법은 표준 OO 관행에 매핑됩니다.
답변
S3 클래스
- 실제로 개체가 아니라 명명 규칙에 가깝습니다.
- . 구문 : 예를 들어 인쇄,
print
호출print.lm
print.anova
등. 찾을 수없는 경우print.default
S4 클래스
- 여러 인수에 디스패치 가능
- S3보다 구현하기가 더 복잡합니다.
참조 클래스
- 큰 개체의 복사본을 만드는 것을 방지하는 데 주로 유용합니다 (참조로 전달).
- RefClass를 사용하는 이유에 대한 설명
프로토
- ggplot2는 원래 proto로 작성되었지만 결국 S3를 사용하여 다시 작성됩니다.
- 깔끔한 개념 (클래스가 아닌 프로토 타입)이지만 실제로는 까다로워 보입니다.
- 다음 버전의 ggplot2가 멀어지는 것 같습니다.
- 개념 및 구현에 대한 설명
R6 클래스
답변
3/8/12에 수정 : 아래 답변은 이후 삭제 된 원래 게시 된 질문에 대한 답변입니다. 내 대답에 대한 컨텍스트를 제공하기 위해 아래에 복사했습니다.
다른 OO 메소드가 예를 들어 Java 또는 Python에서 사용되는보다 표준적인 OO 메소드에 어떻게 매핑됩니까?
내 기여는 R의 OO 방법이 더 표준 OO 방법에 어떻게 매핑되는지에 대한 두 번째 질문과 관련이 있습니다. 과거에 이것에 대해 생각했듯이, 나는 Friedrich Leisch의 한 구절과 John Chambers의 두 구절로 계속해서 돌아 왔습니다. 둘 다 R의 OO와 유사한 프로그래밍이 다른 많은 언어와 다른 풍미를 갖는 이유를 잘 설명합니다.
먼저, “R 패키지 만들기 : 튜토리얼”의 Friedrich Leisch ( 경고 : PDF ) :
S는 상호 작용하고 객체 지향 시스템을 가지고 있기 때문에 드뭅니다. 클래스를 디자인하는 것은 분명히 프로그래밍이지만 S를 대화 형 데이터 분석 환경으로 유용하게 만들기 위해서는 기능적인 언어라는 것이 합리적입니다. C ++ 또는 Java 클래스와 같은 “실제”객체 지향 프로그래밍 (OOP) 언어에서 메서드 정의는 밀접하게 결합되어 있으며 메서드는 클래스의 일부입니다 (따라서 객체). 미리 정의 된 클래스에 대한 사용자 정의 메서드와 같은 점진적 상호 작용 추가를 원합니다. 이러한 추가는 데이터 세트를 분석하는 동안 명령 줄 프롬프트에서 즉석 에서조차도 언제든지 수행 할 수 있습니다. S는 객체 지향과 대화 형 사용 사이에서 타협을 시도하며, 타협이 도달하려는 모든 목표에 대해 최적이 아니지만 실제로는 놀랍도록 잘 작동하는 경우가 많습니다.
다른 구절은 John Chambers의 뛰어난 저서 “Software for Data Analysis” 에서 나옵니다 . ( 인용구에 대한 링크 ) :
OOP 프로그래밍 모델은 S 및 일부 다른 기능 언어가 클래스와 메서드를 지원하더라도 첫 번째 점을 제외하고는 S 언어와 다릅니다. OOP 시스템의 메서드 정의는 클래스에 국한됩니다. 메서드에 대해 동일한 이름이 관련되지 않은 클래스에 대해 동일한 것을 의미 할 필요는 없습니다. 반대로 R의 메서드 정의는 클래스 정의에 있지 않습니다. 개념적으로 그들은 일반 함수와 연관됩니다. 클래스 정의는 직접 또는 상속을 통해 메서드 선택을 결정할 때 입력됩니다. OOP 모델에 익숙한 프로그래머는 프로그래밍이 R로 직접 전송되지 않는다는 사실에 실망하거나 혼란 스러울 때가 있지만 그렇게 할 수는 없습니다. 메서드의 기능적 사용은 더 복잡하지만 의미있는 기능을 갖도록 조정되어 OOP 버전으로 축소 할 수 없습니다.
답변
S3 및 S4는 OO 프로그래밍을위한 공식 (즉, 내장) 접근 방식 인 것 같습니다. S3와 생성자 함수 / 메서드에 포함 된 함수의 조합을 사용하기 시작했습니다. 내 목표는 object $ method () 유형 구문을 사용하여 반 개인 필드를 갖는 것입니다. 나는 그들을 정말로 숨길 방법이 없기 때문에 (내가 아는 한) 반 비공개라고 말합니다. 다음은 실제로 아무것도하지 않는 간단한 예입니다.
#' Constructor
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))
)
#Add a few more methods
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)
}
#' Define S3 generic method for the print function.
print.EmailClass <- function(x) {
if(class(x) != "EmailClass") stop();
cat(paste(x$get("name"), "'s email address is ", x$get("email"), sep=''))
}
그리고 일부 테스트 코드 :
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')
다음은이 접근 방식에 대해 작성한 블로그 게시물에 대한 링크입니다. http://bryer.org/2012/object-oriented-programming-in-r 이 접근 방식 에 대한 의견, 비판 및 제안을 환영합니다. 이것이 최선의 방법이라면 나 자신. 그러나 내가 해결하려고 노력한 문제는 훌륭하게 작동했습니다. 특히 makeR 패키지 ( http://jbryer.github.com/makeR )의 경우 내 개체의 상태를 나타내는 XML 파일이 동기화 상태를 유지해야했기 때문에 사용자가 데이터 필드를 직접 변경하는 것을 원하지 않았습니다. 사용자가 문서에 설명 된 규칙을 준수하는 한 완벽하게 작동했습니다.