例如,我有以下类层次结构:
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]())
实现此功能的正确方法是什么?可能吗?也许有更好的架构决策来实现这个目标?
UPDATE:这里的代码是伪代码,我只是不知道如何写出我想要的东西。
更新2 :我想通过映射可以实现调用类型特定的方法,例如b()
或c()
:
groupC.as.map(_.c())
如果类型参数化正确,则仅可能。这更接近我的想法,但确切的实现方式仍然是个谜(除了asInstanceOf
事物的一堆用法之外)..
答案 0 :(得分: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()
^