使用trait作为scala中的通用接口

时间:2013-05-03 23:15:32

标签: scala generics casting traits

我有一个伪通用类工厂,我正在用于DAO目的。操作模型非常简单:
1)工厂在知道特定DAO对象“T”的情况下实例化 2)然后它创建一个T
的内部实例 3)它应该称为T
的特征契约函数 4)最后,返回T的实例(假设一切顺利)

看起来像这样:

class DAOFactory[T](implicit m: Manifest[T]) {
   def obj = m.runtimeClass.asInstanceOf[Class[T]]
   def doFoo(): Option[Any] = {
       val dao = obj.asInstanceOf[DAO]     // (A) this line will crash
       println(obj.toString())    // some.object.called.DAOTodo
       // val bar = dao.doSomethingSmart(now)   <--- ALL DAO-derived classes implement this function
       return Some(obj) // error-catching excluded for brevity 
   }
}

它的用法如下:
    val f = new DAOFactory [DAOTodo]
    val shinyNewObject = f.doFoo()//永远不会到达。

其中'DAOTodo'实际上是一个实现DAO特征的类:

class DAOTodo extends DAO {
   def doSomethingSmart(when: Whenever) = {...}
}

问:在“A”点需要做什么才能使用DAO作为“obj”的“doSomethingSmart”功能的接口?

提前致谢。

解答: 除了下面答案中概述的代码修改之外,由于创建的类(在工厂内)的谱系具有未实现的主构造函数,因此未按预期运行。创建一个额外的零参数构造函数解决了这个问题。

2 个答案:

答案 0 :(得分:4)

尝试更改此行:

val dao = obj.asInstanceOf[DAO] 

对此:

val dao = obj.newInstance().asInstanceOf[DAO] 

您无法将Class[T]强制转换为DAO特征的实例,因此我假设您想要做的是从类类型中实例化一个新实例。

但为了使它更好,你可以这样定义你的工厂:

class DAOFactory[T <: DAO](implicit m: Manifest[T]) {

然后将该行更改为:

val dao = obj.newInstance()

删除强制转换是可能的,因为您正在约​​束T的类型以包含DAO特征。

将所有内容放在一起(使用几个小mod),使用Scala 2.10成功运行此代码:

import java.util.Date

object DAOTest{
  def main(args: Array[String]) {
    val fact = new DAOFactory[DAOTodo]
    fact.doFoo
  }
}

class DAOFactory[T <: DAO](implicit m: Manifest[T]) {
   def obj = m.runtimeClass.asInstanceOf[Class[T]]
   def doFoo(): Option[Any] = {
     val dao = obj.newInstance()
     println(obj.toString())
     val bar = dao.doSomethingSmart(new Date) 
     return Some(obj) 
   }
}

class DAOTodo extends DAO {
   def doSomethingSmart(date:Date) = {}
}

trait DAO{
  def doSomethingSmart(date:Date)
}

答案 1 :(得分:0)

对我而言,就像你出于错误的原因使用Manifest一样。您应该使用反射Api中的运行时反射。清单是针对参数化类型的类型擦除。 您需要的是这里解释的:http://docs.scala-lang.org/overviews/reflection/overview.html