我正在使用惊人数量的抽象来构建ubercool应用程序。 现在我将设计过度设计的EntityGetService。
我想要的第一件事是很多抽象类型,比如说:
trait EntityGetService[ID, ENTITY, CONTAINER] {
def get(id: ID): CONTAINER
}
这里的CONTAINER是包含(或不包含)请求实体的东西的类型。与Option [ENTITY]非常相似。但我想要的第二件事,那个CONTAINER也可以成为未来[ENTITY]。
所以我真想写这样的特质:
trait EntityGetService[ID, ENTITY, CONTAINER <: Wrapper[ENTITY]] {
def get(id: ID): CONTAINER
}
并以这种方式指定:
trait EntitySyncGetService[Long, Entity, Option[Entity]] {
def get(id: Long): Option[Entity]
}
trait EntityAsyncGetService[Long, Entity, Future[Entity]] {
def get(id: Long): Future[Entity]
}
有没有办法在不重新扩展或混合选项和未来的情况下做到这一点?
看起来Option和Future有一些共同点(它们的两个容器)。它与monads有关吗?
或者这只是我失眠的产物?
答案 0 :(得分:3)
不评论这一切的合理性,您可以使用更高阶的类型:
trait WrappedGetService[ID, ENTITY, WRAPPER[_]] {
def get(id: ID) : WRAPPER[ENTITY]
}
然后您可以声明WrappedGetService[Long, Entity, Option]
。
更新:一些参考
该功能称为高阶类型(可能还有高级类型)或类型构造函数。
答案 1 :(得分:3)
你可以通过我称之为“手动AOP”的一点来实现这一点。
首先定义一些基本特征,以捕获将结果包装在Option
,Future
或任何其他容器中的概念,以及实际执行包装的方法:
import concurrent._
trait AbstractService {
type Result[T]
protected def result[T]( code: => T ) : Result[T]
}
然后为Future
和Option
案例专门化这个基本特征:
trait SyncService extends AbstractService {
type Result[T] = Option[T]
// Returns the original result wrapped in Some,
// or None if it was null or an exception occured
protected def result[T]( code: => T ) : Option[T] = {
try {
Option( code )
} catch{ case ex: Throwable =>
ex.printStackTrace()
None
}
}
}
trait AsyncService extends AbstractService {
type Result[T] = Future[T]
protected val execContext: ExecutionContext
protected def result[T]( code: => T ) : Future[T] = {
future( code )( execContext )
}
}
现在你很高兴能够定义你的EntityGetService特性:
trait EntityGetService[ID, ENTITY] extends AbstractService {
def get( id: ID ): Result[ENTITY] = result {
???
}
// add all the other method implementations here, taking care to
// wrap the method bodies inside "result"
}
// Now specializing EntityGetService as a sync or async service is just a matter
// of mixing SyncService or AsyncService:
class EntitySyncGetService[Long, Entity] extends EntityGetService[Long, Entity] with SyncService
class EntityAsyncGetService[Long, Entity]( implicit val execContext: ExecutionContext ) extends EntityGetService[Long, Entity] with AsyncService