Programowanie obiektowe w taki czy inny sposób jest bardzo możliwe w R. Jednak w przeciwieństwie do np. Pythona, istnieje wiele sposobów na osiągnięcie orientacji obiektowej:

Moje pytanie brzmi:

Jakie główne różnice wyróżniają te sposoby programowania obiektowego w języku R?

Idealnie odpowiedzi tutaj będą służyć jako punkt odniesienia dla programistów R, którzy próbują zdecydować, które metody programowania OO najlepiej odpowiadają ich potrzebom.

W związku z tym proszę o szczegóły, przedstawione w sposób obiektywny, oparty na doświadczeniu, poparty faktami i referencjami. Dodatkowe punkty za wyjaśnienie, w jaki sposób te metody są powiązane ze standardowymi praktykami obiektowymi.

oop r
81
Paul Hiemstra 1 marzec 2012, 22:16

3 odpowiedzi

Najlepsza odpowiedź

Klasy S3

  • Nie tak naprawdę obiekty, raczej konwencja nazewnictwa
  • Oparta na . składnia: Np. do druku, print wywołuje print.lm print.anova, itd. A jeśli nie znaleziono, print.default

Klasy S4

Klasy referencyjne

proto

  • ggplot2 został pierwotnie napisany w wersji proto, ale ostatecznie zostanie przepisany przy użyciu S3.
  • Zgrabna koncepcja (prototypy, nie klasy), ale w praktyce wydaje się trudna
  • Wygląda na to, że następna wersja ggplot2 się od niego odchodzi
  • Opis koncepcji i realizacji

Klasy R6

  • Przez odniesienie
  • Nie zależy od klas S4
  • "Tworzenie klasy R6 jest podobne do klasy referencyjnej, z tą różnicą, że nie ma potrzeby rozdzielania pól i metod i nie możesz określić typów pól."
34
Community 23 maj 2017, 15:10

Edytuj w dniu 8.03.12: poniższa odpowiedź dotyczy fragmentu pierwotnie opublikowanego pytania, które zostało usunięte. Skopiowałem go poniżej, aby zapewnić kontekst dla mojej odpowiedzi:

W jaki sposób różne metody obiektowe odwzorowują się do bardziej standardowych metod obiektowych używanych m.in. Java czy Python?


Mój wkład dotyczy twojego drugiego pytania, o to, jak metody OO w R są odwzorowywane na bardziej standardowe metody OO. Ponieważ myślałem o tym w przeszłości, wracałem raz za razem do dwóch fragmentów, jednego autorstwa Friedricha Leischa, a drugiego autorstwa Johna Chambersa. Oba dobrze sobie radzą, wyjaśniając, dlaczego programowanie w stylu OO w R ma inny smak niż w wielu innych językach.

Najpierw Friedrich Leisch, z „Tworzenie pakietów R: samouczek” (ostrzeżenie: PDF ):

S jest rzadkością, ponieważ jest zarówno interaktywna, jak i posiada system obiektowej orientacji. Projektowanie klas to oczywiście programowanie, jednak aby uczynić S użytecznym jako interaktywne środowisko analizy danych, sensowne jest, aby był to język funkcjonalny. W „prawdziwych” językach programowania obiektowego (OOP), takich jak C++ lub Java, definicje klas i metod są ściśle ze sobą powiązane, metody są częścią klas (a więc i obiektów). Chcemy przyrostowych i interaktywnych dodatków, takich jak metody zdefiniowane przez użytkownika dla predefiniowanych klas. Te dodatki można wprowadzić w dowolnym momencie, nawet w locie, w wierszu poleceń, gdy analizujemy zestaw danych. S stara się znaleźć kompromis między orientacją obiektową a interaktywnym wykorzystaniem i chociaż kompromisy nigdy nie są optymalne w odniesieniu do wszystkich celów, które starają się osiągnąć, często sprawdzają się zaskakująco dobrze w praktyce.

Drugi fragment pochodzi ze znakomitej książki Johna Chambersa "Oprogramowanie do analizy danych" . (Link do cytowanego fragmentu):

Model programowania OOP różni się od języka S we wszystkim poza pierwszym punktem, mimo że S i niektóre inne języki funkcjonalne obsługują klasy i metody. Definicje metod w systemie OOP są lokalne dla klasy; nie ma wymogu, aby ta sama nazwa metody oznaczała to samo dla niepowiązanej klasy. W przeciwieństwie do tego, definicje metod w R nie znajdują się w definicji klasy; koncepcyjnie są one związane z funkcją generyczną. Definicje klas wprowadzane są przy określaniu wyboru metody, bezpośrednio lub poprzez dziedziczenie. Programiści przyzwyczajeni do modelu OOP są czasami sfrustrowani lub zdezorientowani, że ich programowanie nie przenosi się bezpośrednio do R, ale nie może. Funkcjonalne wykorzystanie metod jest bardziej skomplikowane, ale także bardziej dostosowane do posiadania znaczących funkcji i nie może być zredukowane do wersji OOP.

19
Josh O'Brien 8 marzec 2012, 21:44

S3 i S4 wydają się być oficjalnymi (tj. wbudowanymi) podejściami do programowania obiektowego. Zacząłem używać kombinacji S3 z funkcjami osadzonymi w funkcji/metodzie konstruktora. Moim celem było stworzenie składni typu object$method(), aby mieć półprywatne pola. Mówię pół-prywatne, ponieważ tak naprawdę nie ma możliwości ich ukrycia (o ile wiem). Oto prosty przykład, który w rzeczywistości nic nie robi:

#' 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=''))
}

I jakiś kod testowy:

    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')

Oto link do wpisu na blogu, który napisałem o tym podejściu: http://bryer .org/2012/object-orientated-programming-in-r Z zadowoleniem przyjmę komentarze, krytykę i sugestie dotyczące tego podejścia, ponieważ sam nie jestem przekonany, czy jest to najlepsze podejście. Jednak w przypadku problemu, który próbowałem rozwiązać, zadziałało to świetnie. W szczególności w przypadku pakietu makeR (http://jbryer.github.com/makeR) nie chciałem użytkowników do bezpośredniej zmiany pól danych, ponieważ musiałem upewnić się, że plik XML reprezentujący stan mojego obiektu pozostanie zsynchronizowany. Działało to doskonale, o ile użytkownicy przestrzegali zasad, które nakreśliłem w dokumentacji.

14
jbryer 2 marzec 2012, 02:55