Rでは、何らかの方法でオブジェクト指向プログラミングが非常に可能です。ただし、たとえばPythonとは異なり、オブジェクト指向を実現するには多くの方法があります。
私の質問は:
どのようなmajorの違いが、これらのOO Rプログラミングの方法?
理想的には、ここでの答えは、どのOOプログラミング方法が彼らのニーズに最適であるかを決定しようとするRプログラマーのための参照として役立ちます。
そのため、私は詳細を求め、経験に基づいて客観的な方法で提示され、事実と参照に裏付けられています。明確にするためのボーナスポイントhowこれらのメソッドは、標準OOプラクティスにマップします。
S3クラス
print
はprint.lm
print.anova
などを呼び出します。見つからない場合は、print.default
S4クラス
参照クラス
proto
R6クラス
3/8/12に編集:以下の回答は、最初に投稿された質問の一部に対応しており、その後削除されています。私の答えのコンテキストを提供するために、以下にコピーしました:
さまざまなOOメソッドを、たとえばで使用されるより標準的なOOメソッドにどのようにマッピングしますか。 JavaまたはPython?
私の貢献は、RのOOメソッドがより標準的なOOメソッドにどのようにマッピングされるかという2番目の質問に関連しています。過去にこれについて考えてきたように、私は何度も何度も2つのパッセージに戻りました。1つはフリードリッヒライシュ、もう1つはジョンチェンバーズです。どちらも、RでのOOのようなプログラミングが他の多くの言語と異なる風味を持っている理由を明確に説明しています。
最初に、フリードリッヒ・ライシュ、「Rパッケージの作成:チュートリアル」( warning:PDF ):
Sは、インタラクティブであり、オブジェクト指向のシステムを備えているため、まれです。クラスの設計は明らかにプログラミングですが、Sをインタラクティブなデータ分析環境として有用にするためには、関数型言語であることは理にかなっています。 C++やJavaクラスおよびメソッド定義のような「実際の」オブジェクト指向プログラミング(OOP)言語では、メソッドとクラスの定義が緊密に結合されているため、メソッドはクラス(およびオブジェクト)の一部です。事前に定義されたクラスのユーザー定義メソッドのような、インクリメンタルでインタラクティブな追加が必要です。これらの追加は、データセットの分析中にコマンドラインプロンプトで実行中であっても、いつでも行うことができます。 Sは、オブジェクト指向とインタラクティブな使用との間で妥協を試みます。妥協は、到達しようとするすべての目標に関して決して最適ではありませんが、実際には驚くほどうまく機能します。
もう1つは、John Chambersの素晴らしい本 「データ分析用ソフトウェア」 からの引用です。 ( 引用文へのリンク ):
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", "[email protected]")
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("[email protected]")
test$getHistory()
test$sendMail("[email protected]")
test$getNumMessagesSent()
test2 <- EmailClass("Nobody", "[email protected]")
test2
test2$props
test2$getHistory()
test2$sendMail('[email protected]')
このアプローチについて書いたブログ記事へのリンクは次のとおりです。 http://bryer.org/2012/object-oriented-programming-in-r へのコメント、批判、提案を歓迎しますこれが最良のアプローチであるかどうか私は確信していないので、このアプローチ。しかし、私が解決しようとしていた問題についてはうまくいきました。具体的には、makeRパッケージ( http://jbryer.github.com/makeR )の場合、オブジェクトの状態を表すXMLファイルを確認する必要があるため、ユーザーがデータフィールドを直接変更したくない同期を維持します。これは、ユーザーがドキュメントで説明した規則を順守している限り、完全に機能しました。