12

実際の質問

R6が多重継承をサポートしていないという事実を回避するためのオプションは何ですか?

免責事項

R は基本的に関数型言語であることは知っています。ただし、非常に強力なオブジェクト指向も組み込まれてます。さらに、OOD の原則/動作を模倣することの何が問題なのかわかりません。

  1. C#、Java などのオブジェクト指向言語のプロトタイピングを行っていることを知っています。

  2. アプリのプロトタイプは、自己完結型である必要があります(DB バックエンド、ビジネス ロジック、フロントエンド/UI を含む「フル スタック」)。

  3. あなたはR6のような素晴らしい「プロトタイピング技術」を持っていて、自由に使うことができます

環境

Web アプリ用の私の R プロトタイプは、「フル スタック」/自己完結型あり本番環境言語( C#/.ネット)。

その点で、コード モジュールを切り離し、OOD の SOLID 原則のD (依存性反転の原則)に準拠するために、インターフェイス (または抽象クラス) の使用が非常に好きになりました( 「ボブおじさん」による詳細な説明)。 )。

R6 はインターフェイスを明示的にサポートしていませんが、「抽象メソッド」のみを定義する R6 クラスで完全に模倣できます(以下の例を参照)。これは、R にあまり詳しくない OO プログラマーに私のソフトウェア設計を伝えるのに非常に役立ちます。

ただし、実際に他の具象から継承したい場合(「 abstractのような」模倣されたインターフェイス クラスとは対照的に) には、少し問題になるinheritinの値を放棄する必要があります。しかし、 の 2 つのクラス。R6Classinherit

依存関係の反転前:

Foo具体的なクラスに依存しBarます。OOD 原則の観点からは、コードが密結合になるため、これはかなり悪いことです。

Bar <- R6Class("Bar",
  public = list(doSomething = function(n) private$x[1:n]),
  private = list(x = letters)
)
Foo <- R6Class("Foo",
  public = list(bar = Bar$new())
)
inst <- Foo$new()
> class(inst)
> class(inst$bar)
[1] "Bar" "R6" 

依存関係の反転後:

FooBar現在は切り離されています。どちらも、 class によって模倣されるインターフェースに依存していますIBar。実行時に のインスタンスにプラグインするインターフェイスの実装を決定できFooます (プロパティ インジェクション: のフィールドbarによって実現Foo)

IBar <- R6Class("IBar",
  public = list(doSomething = function(n = 1) stop("I'm the inferace method"))
)
Bar <- R6Class("Bar", inherit = IBar,
  public = list(doSomething = function(n = 1) private$x[1:n]),
  private = list(x = letters)
)
Baz <- R6Class("Baz", inherit = IBar,
  public = list(doSomething = function(n = 1) private$x[1:n]),
  private = list(x = 1:24)
)
Foo <- R6Class("Foo",
  public = list(bar = IBar$new())
)

inst <- Foo$new()
inst$bar <- Bar$new()
> class(inst$bar)
[1] "Bar"  "IBar" "R6"  
> inst$bar$doSomething(5)
[1] "a" "b" "c" "d" "e"

inst$bar <- Baz$new()
[1] "Baz"  "IBar" "R6"  
> inst$bar$doSomething(5)
[1] 1 2 3 4 5

これがOODに関して理にかなっている理由について少し詳しく説明します。フィールドに格納されたオブジェクトが実装Fooされる方法に完全に依存しない必要があります。知る必要があるのは、そのオブジェクトで呼び出すことができるメソッドだけです。それを知るには、 field 内のオブジェクトが実装するインターフェース(私たちの場合は method ) を知るだけで十分です。barbarIBardoSomething()

基本クラスからの継承を使用して設計を簡素化する:

ここまでは順調ですね。ただし、他の具象クラスの一部が継承できる特定の具象基本クラスを定義することで、設計を簡素化したいと考えています。

BaseClass <- R6Class("BaseClass",
  public = list(doSomething = function(n = 1) private$x[1:n])
)
Bar <- R6Class("Bar", inherit = BaseClass,
  private = list(x = letters)
)
Baz <- R6Class("Bar", inherit = BaseClass,
  private = list(x = 1:24)
)

inst <- Foo$new()
inst$bar <- Bar$new()
> class(inst$bar)
[1] "Bar"       "BaseClass" "R6"   
> inst$bar$doSomething(5)
[1] "a" "b" "c" "d" "e"

inst$bar <- Baz$new()
> class(inst$bar)
[1] "Baz"       "BaseClass" "R6"       
> inst$bar$doSomething(5)
[1] 1 2 3 4 5

「インターフェースの実装」と基本クラスの継承を組み合わせる:

これは、多重継承が必要な場所なので、次のようなものが機能します (PSEUDO CODE):

IBar <- R6Class("IBar",
  public = list(doSomething = function() stop("I'm the inferace method"))
)
BaseClass <- R6Class("BaseClass",
  public = list(doSomething = function(n = 1) private$x[1:n])
)
Bar <- R6Class("Bar", inherit = c(IBar, BaseClass),
  private = list(x = letters)
)
inst <- Foo$new()
inst$bar <- Bar$new()
class(inst$bar)
[1] "Bar"       "BaseClass" "IBar" "R6"

現在、私の値inheritは、インターフェイスの実装を模倣するために「ちょうど」使い果たされているため、実際の具象クラスの継承の「実際の」利点を失います。

別の考え:

あるいは、インターフェイス具象クラスの区別を何らかの形で明示的にサポートすることは素晴らしいことです。たとえば、このようなもの

Bar <- R6Class("Bar", implement = IBar, inherit = BaseClass,
  private = list(x = letters)
)
4

2 に答える 2

6

さらに、C#、Java などのオブジェクト指向言語のプロトタイピングを行っていることがわかっているときに、OOD の原則/動作を模倣することの何が悪いのかわかりません。

R は単に OOD システムのプロトタイプを作成するための不十分なツールであり、必要なものをサポートしていないため、この質問をする必要があったことが問題です。

または、データ分析に依存するソリューションの側面のプロトタイプを作成し、パラダイムに適合しない API の側面のプロトタイプを作成しないでください。

とはいえ、R の強みは、独自のオブジェクト システムを記述できることです。結局のところ、それがR6です。R6 はたまたまあなたの目的には不十分ですが、独自のシステムを実装することを妨げるものは何もありません。特に、S3 はすでに複数の継承を許可していますが、コード化されたインターフェイスをサポートしていません (代わりに、アドホックに発生します)。

しかし、このコード化を実行するラッパー関数を提供することを妨げるものは何もありません。たとえば、次のように使用できる一連の関数interfaceを実装できますclass(ただし、名前の衝突に注意してください)。

interface(Printable,
    print = prototype(x, ...))

interface(Comparable,
    compare_to = prototype(x, y))

class(Foo,
    implements = c(Printable, Comparable),
    private = list(x = 1),
    print = function (x, ...) base::print(x$x, ...),
    compare_to = function (x, y) sign(x$x - y$x))

これにより、(たとえば)次のように生成されます。

print.Foo = function (x, ...) base::print(x$x, ...)

compare_to = function (x, y) UseMethod('compare_to')

compare_to.foo = function (x, y) sign(x$x - y$x)

Foo = function ()
    structure(list(x = 1), class = c('Foo', 'Printable', 'Comparable'))

… 等々。実際、S4 も同様のことを行います (ただし、私の意見では悪いことです)。

于 2016-02-15T17:32:07.510 に答える