2012-06-19 82 views
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东西的用法)..

+0

也许使用'Group [C]'的隐式转换为具有'c()'方法的东西,它只适用于参数为“C”的情况? – ziggystar

+0

@ziggystar:也许,但你能举个例子吗?我不确定我能否像那样把握它。 – noncom

回答

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类。请注意0​​的隐式转换,其中添加了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([email protected], [email protected])) 

scala> groupC.c() //works 

scala> val groupB = Group(new B :: new B :: Nil) 
groupB: Group[B] = Group(List([email protected], [email protected])) 

scala> groupB.c() //fails as expected 
<console>:16: error: value c is not a member of Group[B] 
       groupB.c() 
        ^
+0

这绝对好得多!但是,对不起,我有一些问题=):1)case class由于调用自动创建的'as'方法的便利性,所以只能创建* case *类?2)你提到'c()'方法不会产生任何东西。为什么这很重要?你是否认为这纯粹是副作用,这是无法帮助的? 3)我可以在哪里阅读更多关于这里使用的'隐式'形式,以及'new {}'构造的无名类?这个表单是否意味着无名的类实例(?)会继承组[C]中的内容? – noncom

+0

1)'case'类是方便的;它还会将“应用”添加到手动完成的伴侣。 2)是的,评论有点误导。我添加了它,因此读者不会怀疑输出的位置。没有办法,因为这个方法什么都不做。你可以在'c()'中做任何你喜欢的事情。 3)该模式被称为[* Pimp我的图书馆*](http://www.scalaclass.com/node/14);你也可以命名这个班。除非添加'extends C',否则它不会从'C'继承。 – ziggystar

+0

非常感谢! – noncom