24

前もって: R が関数型言語であることは認識しているので、噛まないでください ;-)

私は、多くのプログラムで OOP アプローチを使用して素晴らしい経験を積んできました。さて、 R でS4 参照クラスを使用するときに、パブリックメソッドとプライベートメソッドを区別する方法があるかどうか疑問に思っています。

クラス定義

setRefClass("B",
    field=list(
        b.1="numeric",
        b.2="logical"
    ),
    methods=list(
        thisIsPublic=function(...) {
            thisIsPublic_ref(.self=.self, ...)
        },
        thisIsPrivate=function(...) {
            thisIsPrivate_ref(.self=.self, ...)
        }
    )
)

setRefClass("A",
    field=list(
        a.1="B"
    )
)

ノート

私は通常、実際のthisIsPublic_refメソッド定義をクラス定義内に配置せず、次の理由でS4 メソッド (つまり ) に分離します。

  1. そうすれば、クラス定義は明確に配置されたままになり、個々のメソッド定義が非常に大きくなる場合でも読みやすくなります。
  2. これにより、いつでもメソッドの機能実行に切り替えることができます。特定のクラスのインスタンスになると、 の代わりにx呼び出すことができます。foo_ref(.self=x)x$foo()
  3. compiler::cmpfun()「プレーンな」参照クラスメソッドがある場合は不可能だと思われるメソッドをバイトコンパイルできます。

この特定の例をそれほど複雑にすることは確かに意味がありませんが、それでもそのアプローチを説明したいと思いました。

メソッド定義

setGeneric(
    name="thisIsPublic_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPublic_ref")    
    }
)
setGeneric(
    name="thisIsPrivate_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPrivate_ref")    
    }
)

require(compiler)

setMethod(
    f="thisIsPublic_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.1 * 1000
    })
)
setMethod(
    f="thisIsPrivate_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.2
    })
)

インスタンス

x.b <- new("B", b.1=10, b.2=TRUE)
x.a <- new("A", a.1=x.b, a.2="hello world")

パブリック vs. プライベート

class のインスタンスA(つまり) は、 classのpublicメソッドx.aを使用できるようにする必要があります。B

> x.a$a.1$thisIsPublic()
[1] 10000

class のインスタンスA(つまりx.a) は、 classのプライベートメソッドの使用を許可されるべきではありません。したがって、これが機能しないようにしたいと思います。つまり、エラーが発生します。B

> x.a$a.1$thisIsPrivate()
[1] TRUE

これをどのように指定できますか?

これまでに思いついた唯一のこと:

各メソッドに引数を追加し、senderメソッド呼び出しごとに明示的に指定して、 if を確認しますclass(.self) == class(sender)。しかし、それは少し「明白」に思えます。

4

2 に答える 2

8

関数は R の第一級オブジェクトであるため、次のように一方を他方の内部に埋め込むことができます。

hello <- function() {
    print_ <- function() { 
         return ('hello world')
    }
    print_()
}

はい、生意気です。おそらく最もクリーンな方法ではありませんが、機能します...「hello()」を使用して呼び出します。

于 2012-09-27T15:28:22.450 に答える
3

簡単な答えは、パッケージを作成することです。R のオブジェクト システムとコードを分割する手段 (名前空間) は、Java に似た言語の同等のものよりも分離されています。

exportパッケージを作成するときは、ディレクティブとを使用して、NAMESPACE というファイルにエクスポートするものを指定しますexportMethods。パッケージ プライベートにするメソッドやその他の R オブジェクトをエクスポートしないことを選択できます (Java 用語を使用するため)。R 拡張機能の記述マニュアルの「S4 クラスとメソッドを使用した名前空間」セクションを参照してください。

初めてパッケージを作成するのは難しいですが、役立つことはたくさんあります。package.skeletonのドキュメントと、上記にリンクされているR 拡張機能の記述マニュアルを参照してください。

参照クラスが本当に必要なものであることを確認してください。通常の S4 クラスは、価値が何であれ、通常はより R っぽい方法です。R の多くの OO コンストラクト (およびパッケージングについても) に関する優れた情報源は、Hadley Wickham の devtools wikiにあります。

于 2012-08-30T06:09:38.280 に答える