1

たとえば、次のクラス階層があります。

abstract class A {
  def a() {}
  def aa()
}

class B extends A {
  def aa() {}
  def b()
}

class C extends A {
  def aa() {}
  def c()
}

そして、これらのクラス インスタンスの任意の組み合わせのコレクションを格納できるクラスを作成したいと考えています。一般的なメソッドを呼び出すことができます。また、型のパラメーター化により、作成時にこれらのクラスでパラメーター化されている場合は、クラス固有のメソッドを呼び出す機能を提供する必要があります。

object Group {

  def apply(as: Buffer[A]) = new Group[A](as)
  def apply[T <: A](as: Buffer[T]) = new Group[T](as)
}

class Group[T <: A](as: Buffer[T]) {

  def a() { as.map(_.a()) }
  def aa() { as.map(_.aa()) }

}

したがって、次のGroupようなデフォルトの最も一般的な型パラメーターを使用して作成できます。

val groupA = Group(Buffer[A]())
groupA.a()  //ok
groupA.aa() //ok
groupA.b()  //error
groupA.c()  //error

の子孫の 1 つを使用して明示的にパラメーター化すると作成できますA

val groupB = Group[B](Buffer[B]())
groupB.a()  //ok
groupB.aa() //ok
groupB.b()  //ok
groupB.c()  //error

[B]可能であれば、渡されたバッファタイプから抽出できるため、グループを作成するときに不要なタイプ指定を削除したいと思います。

val groupB = Group(Buffer[B]())

この機能を実現する正しい方法は何ですか? 出来ますか?これを達成するためのより良いアーキテクチャ上の決定があるのでしょうか?

更新:ここのコードは疑似コードです。必要なものを記述する方法がわかりません。

更新 2:b()またはのような型固有のメソッドの呼び出しc()は、マッピングを通じて実現する必要があると思います。

groupC.as.map(_.c())

これは、型のパラメーター化が正しい場合にのみ可能です。それは私の考えに近づきますが、実現可能な正確な方法は謎のままです(asInstanceOf物事の多くの使用法は別として)。

4

1 に答える 1

2

暗黙的な変換を使用Groupして、正しい型でパラメーター化されたインスタンスのみにメソッドを追加するように見えます。これは、 pimp my libraryパターンの選択的バージョンと見なすことができます。

scala> abstract class A { def a() {}; def aa() {} }
defined class A

scala> class B extends A {def b() {}}
defined class B

scala> class C extends A {def c() {}}
defined class C

次に、クラスを定義しますGroupGroup[C]メソッドを追加するための暗黙的な変換に注意してくださいc()。この変換は、Group[A]値などには適用されません。

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Group[T <: A](as: Seq[T])
object Group{implicit def forC(gc: Group[C]) = new {def c() {gc.as.map(_.c())}}}

// Exiting paste mode, now interpreting.

defined class Group
defined module Group

それでは、動作するかどうか見てみましょう。

scala> val groupC = Group(new C :: new C :: Nil)
groupC: Group[C] = Group(List(C@7f144c75, C@da7d681))

scala> groupC.c()  //works

scala> val groupB = Group(new B :: new B :: Nil)
groupB: Group[B] = Group(List(B@e036122, B@7fde065d))

scala> groupB.c()  //fails as expected
<console>:16: error: value c is not a member of Group[B]
              groupB.c()
                     ^
于 2012-06-19T12:09:11.133 に答える