R и объектно-ориентированное программирование - PullRequest
78 голосов
/ 01 марта 2012

Объектно-ориентированное программирование так или иначе очень возможно в R. Однако, в отличие от, например, Python, существует много способов достижения объектной ориентации:

Мой вопрос:

Какие основные различия отличают эти способы программирования ОО в R?

В идеале ответы здесь будут служить ориентиром для программистов R, пытающихся решить, какие методы программирования ОО лучше всего соответствуют их потребностям.

В связи с этим я прошу подробности, представленные объективно, основанные на опыте и подкрепленные фактами и ссылками. Бонусные баллы за разъяснение как эти методы соответствуют стандартным практикам ОО.

Ответы [ 3 ]

33 голосов
/ 01 марта 2012

S3 классы

  • Не совсем объекты, скорее соглашение об именах
  • На основании всего. синтаксис: например, для печати print звонки print.lm print.anova и т. д. А если не найдены, print.default

S4 классы

Справочные классы

прото

  • ggplot2 изначально был написан на Proto, но в конечном итоге будет переписан с использованием S3.
  • Идеальная концепция (прототипы, а не классы), но на практике кажется хитрой
  • Следующая версия ggplot2, похоже, удаляется от него
  • Описание концепции и реализации

R6 классы

  • По ссылке
  • Не зависит от классов S4
  • " Создание класса R6 аналогично эталонному классу, за исключением того, что нет необходимости разделять поля и методы, и вы не можете указывать типы полей."
19 голосов
/ 01 марта 2012

Изменить на 3/8/12: Ответ ниже отвечает на часть первоначально отправленного вопроса, который с тех пор был удален.Я скопировал его ниже, чтобы предоставить контекст для моего ответа:

Как различные методы ОО отображаются на более стандартные методы ОО, используемые, например, в Java или Python?


Мой вклад связан с вашим вторым вопросом о том, как ОО-методы R соответствуют более стандартным ОО-методам.Как я уже думал об этом в прошлом, я снова и снова возвращался к двум отрывкам: один от Фридриха Лейша, а другой от Джона Чемберса.Оба хорошо объясняют, почему ОО-подобное программирование в R отличается от внешнего вида, чем во многих других языках.

Во-первых, Фридрих Лейш, из "Создание пакетов R: Учебное пособие" ( предупреждение:PDF ):

S встречается редко, поскольку он одновременно интерактивен и имеет систему объектной ориентации.Очевидно, что разработка классов - это программирование, но для того, чтобы сделать S полезной в качестве интерактивной среды анализа данных, имеет смысл, что это функциональный язык.В «реальном» объектно-ориентированном программировании (ООП) языки, такие как классы C ++ или Java, и определения методов тесно связаны друг с другом, методы являются частью классов (и, следовательно, объектов).Нам нужны инкрементные и интерактивные дополнения, такие как пользовательские методы для предопределенных классов.Эти дополнения могут быть сделаны в любой момент времени, даже на лету в командной строке, пока мы анализируем набор данных.S пытается найти компромисс между ориентацией на объект и интерактивным использованием, и хотя компромиссы никогда не бывают оптимальными в отношении всех целей, которые они пытаются достичь, на практике они часто работают на удивление хорошо.

Другой отрывокиз превосходной книги Джона Чемберса «Программное обеспечение для анализа данных» .( Ссылка на цитируемый отрывок ):

Модель программирования ООП отличается от языка S во всем, кроме первого пункта, даже несмотря на то, что S и некоторые другие функциональные языки поддерживают классы и методы,Определения методов в системе ООП являются локальными для класса;не требуется, чтобы одно и то же имя метода означало то же самое для несвязанного класса.Напротив, определения методов в R не находятся в определении класса;концептуально они связаны с общей функцией.Определения классов вводятся при определении метода выбора напрямую или через наследование.Программисты, привыкшие к модели ООП, иногда расстраиваются или смущаются тем, что их программирование не передается непосредственно в R, но не может.Функциональное использование методов является более сложным, но также более приспособленным к наличию значимых функций и не может быть уменьшено до версии ООП.

14 голосов
/ 02 марта 2012

S3 и S4 кажутся официальными (то есть встроенными) подходами для ОО-программирования.Я начал использовать комбинацию 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, представляющий состояние моего объекта, будет синхронизирован. Это работало идеально, пока пользователипридерживайтесь правил, изложенных в документации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...