这种方法可行,但当类型参数的数量增加时,您可能会遇到问题。也许一个解决方案是使用抽象类型成员而不是类型参数。
另一种方法是使用我认为在您的情况下提供更好解决方案的蛋糕模式。你的代码的确切逻辑让我有点难以理解,所以这个重写可能并不完全代表你的意图:
package foolib.generic
//defines common types used by all modules
trait CoreModule {
type Id // abstract type, not commited to any particular implementation
}
//module defining the EntityModule trait
trait EntityModule { this: CoreModule => //specifying core module as a dependency
trait GenEntity {
def id: Id
}
def mkEntity(id: Id): Entity //abstract way of creating an entity
}
//defines the GenRepository trait
trait RepositoryModule { this: EntityModule with CoreModule => //multiple dependencies
trait GenRepository {
def getById(id: Id): GenEntity
}
val repository: GenRepository //abstract way of obtaining a repository
}
//concrete implementation for entity
trait EntityImplModule extends EntityModule { this: CoreModule =>
case class Entity(val id: Id) extends GenEntity
def mkEntity(id: Id) = Entity(id)
}
//modules that provides a concrete implementation for GenRepository
trait RepositoryImplModule extends RepositoryModule { this: CoreModule with EntityModule =>
object RepositoryImpl extends GenRepository {
def getById(id: Id) = mkEntity(id)
}
}
//this unifies all your modules. You can also bind any dependencies and specify any types
object Universe
extends CoreModule
with EntityImplModule
with RepositoryImplModule {
type Id = java.util.UUID
val repository = RepositoryImpl
def mkEntity(id: Id) = Entity(id)
}
//usage
object Main {
import Universe._
import java.util.UUID
val entity = repository.getById(UUID.randomUUID())
println(entity.id)
}
这实现了创建独立于具体类型 Id 的实现的目标,并且还提供了一种进行依赖注入的好方法。
例如,为 提供具体实现的模块GenRepository
可能需要Id
. 您可以很好地创建另一个绑定Id
到具体类型的模块并使其RepositoryImplModule
依赖于前一个模块,从而指定此具体实现GenRepository
仅适用于某种类型的 id。
Cake 模式非常强大,并且有很多变化。该视频解释得很好,如果您对此解决方案感兴趣,我建议您观看:
蛋糕图案:来自黑湖的面包店