我有一个看起来像这样的特质书
trait Book{
val sqlTableName;
def getAll: Seq[ Book ] = { magicSQLFn( $"SELECT * FROM $sqlTableName" ) }
}
我有两种派生类型:
class Fiction extends Book{ val sqlTableName = "fiction" }
class NonFiction extends Book{ val sqlTableName = "nonfiction" );
当我在Seq[Fiction]
的实例上调用getAll
时,我需要Fiction
,fiction1
。我知道一种方法是做.map( _.asInstanceOf[ Fiction ] )
。但是,有没有办法完全避免这种情况?
实际上,我意识到错误的方法是能够为Fiction
定义一个扩展Book
的伴随对象,以便我可以在该对象上调用getAll
(然而,在这种情况下,我不确定如何将返回序列中的各个元素转换为Fiction
类的实例,因为Fiction
类将不再来自Book
。
我应该有两个不同名称的Book
特征吗?一个是这些对象的超级,另一个是这些类的超类?
答案 0 :(得分:9)
这或多或少是F-bounded polymorphism的经典用例,它允许您在超类型的方法中引用特定的子类型:
trait Book[B <: Book[B]] {
val sqlTableName;
def getAll: Seq[B] = { magicSQLFn( $"SELECT * FROM $sqlTableName" ) }
}
class Fiction extends Book[Fiction] { val sqlTableName = "fiction" }
class NonFiction extends Book[NonFiction] { val sqlTableName = "nonfiction" )
(这假设您的magicSQLFn
将返回具有相应静态类型的内容,但毕竟它是神奇的。)
F -bounded polymorphism has its detractors,有一些需要注意的问题,但它在Scala和Java中都是一个相当广泛使用的模式。