Rおよびオブジェクト指向プログラミング


80

Rでは、何らかの方法でオブジェクト指向プログラミングを行うことができます。ただし、たとえばPythonとは異なり、オブジェクト指向を実現する方法はたくさんあります。

私の質問は:

Rでのオブジェクト指向プログラミングのこれらの方法を区別する主な違いは何ですか?

理想的には、ここでの回答は、どのOOプログラミング方法が彼らのニーズに最も適しているかを決定しようとするRプログラマーのための参照として役立つでしょう。

そのため、私は詳細を求め、経験に基づいて客観的に提示し、事実と参照に裏打ちされています。これらの方法が標準のOOプラクティスにどのようにマッピングされるを明確にするためのボーナスポイント。


1
参照クラスに関する情報:stackoverflow.com/questions/5137199/…–
Ari B. Friedman

ありがとう、答えとしてリンクを再投稿できますか?参照クラスとは何か、およびS3 / S4クラスに関連してそれらが望ましい理由の簡単な要約を含めることができれば便利です。
Paul Hiemstra 2012年

小鳥が私の耳にささやき、これに関する本がジョン・チェンバースから出版される予定です。しかし、私が言ったことを誰にも言わないでください... ;-)
Dirk Eddelbuettel 2012年

1
同じ小さな鳥が、以下の回答にRefenenceクラスに関する詳細情報を貼り付けることができますか;)
Paul Hiemstra 2012年

回答:


34

S3クラス

  • 実際にはオブジェクトではなく、命名規則の詳細
  • に基づいています。構文:たとえば、印刷、print呼び出しprint.lm print.anovaなど。見つからない場合は、print.default

S4クラス

参照クラス

プロト

  • ggplot2は元々protoで書かれていましたが、最終的にはS3を使用して書き直されます。
  • きちんとした概念(クラスではなくプロトタイプ)ですが、実際には注意が必要です
  • ggplot2の次のバージョンはそれから遠ざかっているようです
  • コンセプトと実装の説明

R6クラス

  • 参照による
  • S4クラスに依存しません
  • 「R6クラスの作成は、フィールドとメソッドを分離する必要がなく、フィールドのタイプを指定できないことを除いて、参照クラスと似ています。」

1
追加する他の違いがある場合は、自由に編集してください。CWになっても泣きません:-)
Ari B. Friedman

3
忘れないでくださいlibrary("fortunes"); fortune("strait")
ベンボルカー2012年

1
ここでS4クラスに関する議論:stackoverflow.com/questions/3602154/…。一般的な感覚は、彼らが利点をもたらすよりも厄介であるということのようです。
Paul Hiemstra 2012年

興味深いことに、新しいR6クラスは、その番号の使用を回避することにより、参照クラスがR5であることを暗黙的に認識します。論争を(新たに)始めましょう。
アリB.フリードマン

1
R5という名前は、元々、参照クラスの開発者以外の人々によって冗談として使用されていました。R6という名前は「R5」の承認ですが、R5という名前が公式に承認されたことを意味するものではありません。
wch 2014

19

2012年3月8日に編集:以下の回答は、最初に投稿された質問の一部に対応していますが、その後削除されました。私の答えのコンテキストを提供するために、以下にコピーしました。

さまざまなOOメソッドは、JavaやPythonなどで使用されるより標準的なOOメソッドにどのようにマッピングされますか?


私の貢献は、RのOOメソッドがより標準的なOOメソッドにどのようにマッピングされるかについての2番目の質問に関連しています。過去にこれについて考えたように、私は何度も何度も2つのパッセージに戻りました。1つはフリードリッヒ・ライシュによるもので、もう1つはジョン・チェンバースによるものです。どちらも、RでのOOのようなプログラミングが他の多くの言語とは異なるフレーバーを持っている理由を明確に表現しています。

まず、「Rパッケージの作成:チュートリアル」(警告:PDF)のFriedrich Leisch :

Sはインタラクティブであり、オブジェクト指向のシステムを備えているため、まれです。クラスの設計は明らかにプログラミングですが、Sをインタラクティブなデータ分析環境として役立つようにするためには、関数型言語であることは理にかなっています。C ++やJavaクラスなどの「実際の」オブジェクト指向プログラミング(OOP)言語では、メソッド定義は緊密にバインドされており、メソッドはクラス(したがってオブジェクト)の一部です。事前定義されたクラスのユーザー定義メソッドのような増分的でインタラクティブな追加が必要です。これらの追加は、データセットの分析中にコマンドラインプロンプトでその場で行う場合でも、いつでも行うことができます。Sは、オブジェクト指向とインタラクティブな使用の間で妥協しようとします。妥協は、達成しようとするすべての目標に関して最適ではありませんが、実際には驚くほどうまく機能することがよくあります。

もう1つの節は、JohnChambersのすばらしい本「SoftwareforDataAnalysis」からのものです。(引用された一節へのリンク):

Sや他のいくつかの関数型言語はクラスとメソッドをサポートしていますが、OOPプログラミングモデルは最初の点を除いてすべてS言語とは異なります。OOPシステムのメソッド定義はクラスに対してローカルです。メソッドの同じ名前が、無関係のクラスの同じことを意味する必要はありません。対照的に、Rのメソッド定義はクラス定義に存在しません。概念的には、これらは汎用関数に関連付けられています。クラス定義は、直接または継承を通じて、メソッドの選択を決定する際に入力されます。OOPモデルに慣れているプログラマーは、プログラミングがRに直接転送されないことに不満を感じたり、混乱したりすることがありますが、転送することはできません。メソッドの機能的な使用はより複雑ですが、意味のある機能を持つように調整されており、OOPバージョンに還元することはできません。


14

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-directiond-programming-in-r確信が持てないため、このアプローチに対するコメント、批判、提案を歓迎します。これが最善のアプローチである場合は自分自身。しかし、私が解決しようとしていた問題については、うまくいきました。具体的には、makeRパッケージ(http://jbryer.github.com/makeR)の場合、オブジェクトの状態を表すXMLファイルの同期を維持する必要があるため、ユーザーがデータフィールドを直接変更することを望まなかった。これは、ユーザーがドキュメントで概説したルールを順守している限り、完全に機能しました。


10
あなたは上記のコードを使って「手作業で」参照クラスを再発明しているようなものです...それは物事をかなり壊れやすくします。
サイモン・ウルバネク2012年

サイモンに感謝します。これを投稿するまで、ReferenceClassesに気づいていませんでした。
jbryer 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.