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

并且可以在使用 的后代之一显式参数化时创建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

现在我定义Group类。请注意Group[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 回答